tag:blogger.com,1999:blog-48154817344540814912026-04-12T23:57:18.362-07:00Minborg's Java PotThis is my Java blog with various tips and tricks that are targeted for medium and advanced Java users.
I work as a Java Core Library Developer at Oracle. The views on this blog are my own and are not necessarily the ones of Oracle, Inc.
Happy Reading! /Per MinborgPer Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.comBlogger124125tag:blogger.com,1999:blog-4815481734454081491.post-32311954077526759432024-01-15T07:19:00.000-08:002024-01-15T07:19:54.375-08:00Statistics for the 1BRC Java Challenge<div class="sect1 has-source-line data-line-stdin-6" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 0.625em;"><h2 id="_introduction" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-style: normal; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;">Introduction</h2><h2 class="" data-react-autofocus="true" dir="auto" id="user-content-introduction" style="border-bottom: 1px solid var(--borderColor-muted, var(--color-border-muted)); box-sizing: border-box; font-size: 1.5em; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;" tabindex="-1"><div class="sect1 has-source-line data-line-stdin-6" style="box-sizing: border-box; font-size: 16px; font-weight: 400; margin: 0px; padding: 0px 0px 0.625em;"><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-7" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">It is hard to avoid hearing about <a href="https://github.com/gunnarmorling/1brc" style="background: none; box-sizing: border-box; color: #589df6; line-height: inherit;">Gunnar Morling’s "One Billion Row Challenge"</a> these days, where the objective is to parse and compute the min, average and max value for various weather stations using the Java language. The data to analyze is a semicolon-separated list of rows that looks like this:</p></div><div class="listingblock has-source-line data-line-stdin-10" style="box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.8125em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;">Hamburg;12.0
Bulawayo;8.9
Palembang;38.8
St. John's;15.2
Cracow;12.6
Bridgetown;26.9
Istanbul;6.2
Roseau;34.4
Conakry;31.2
Istanbul;23.0</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-23" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">As indicated by the name of the project, there are one billion such rows. I have struggled for several weeks <strong style="box-sizing: border-box; letter-spacing: -0.005em; line-height: inherit;">not</strong> to enter the competition.</p></div><div class="paragraph has-source-line data-line-stdin-25" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Anyway, I suspect there are some gains to be harvested if one knows the distribution of the values in the generated <code style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">measurement.txt</code> file of size 13 GiB (hereafter called "the file") and in this short article, I want to share my findings.</p></div></div></div></h2><h2 id="_name_statistics" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;">Name Statistics</h2><h2 class="" data-react-autofocus="true" dir="auto" style="border-bottom: 1px solid var(--borderColor-muted, var(--color-border-muted)); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;" tabindex="-1"><div class="sect1 has-source-line data-line-stdin-27" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-size: 16px; font-weight: 400; margin: 0px; padding: 0px 0px 0.625em;"><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-29" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">The names are UTF-8 coded and can occupy up 100 bytes of space.</p></div><div class="paragraph has-source-line data-line-stdin-31" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Looking at the file, one can conclude that there are <strong style="box-sizing: border-box; letter-spacing: -0.005em; line-height: inherit;">413 distinct names</strong>. So, the number of stations is actually relatively limited. Holding these in hash tables or the like is not anticipated to take up a significant amount of memory.</p></div></div></div></h2><h3 id="_length" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.375em; font-weight: 300; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;">Length</h3><h2 class="" data-react-autofocus="true" dir="auto" style="border-bottom: 1px solid var(--borderColor-muted, var(--color-border-muted)); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;" tabindex="-1"><div class="sect1 has-source-line data-line-stdin-27" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-size: 16px; font-weight: 400; margin: 0px; padding: 0px 0px 0.625em;"><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="sect2 has-source-line data-line-stdin-33" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-35" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Taking a look at the distribution of the byte length (as opposed to the UTF-8 length) of the various names (if decoded by <code style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">String::getBytes</code>), we can see the following,</p></div><table class="tableblock frame-all grid-all stretch has-source-line data-line-stdin-38" style="background: rgb(255, 255, 255); border-collapse: collapse; border-spacing: 0px; border: 1px solid rgb(222, 222, 222); color: #bbbbbb; margin-bottom: 1.25em; overflow-wrap: normal; width: 585px;"><colgroup style="box-sizing: border-box;"><col style="box-sizing: border-box; width: 292px;"></col><col style="box-sizing: border-box; width: 292px;"></col></colgroup><thead style="background: rgb(98, 98, 98); box-sizing: border-box;"><tr style="box-sizing: border-box;"><th class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5em 0.625em 0.625em; text-align: left; text-rendering: optimizelegibility; vertical-align: top;">Size</th><th class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5em 0.625em 0.625em; text-align: left; text-rendering: optimizelegibility; vertical-align: top;">Frequency</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">3</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">18</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">5</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">42</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">6</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">87</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">7</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">66</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">8</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">57</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">9</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">47</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">10</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">26</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">11</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">26</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">12</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">17</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">13</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">9</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">14</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">15</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">16</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">6</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">17</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">1</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">18</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">1</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">24</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">1</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">26</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">1</p></td></tr></tbody></table><div class="paragraph has-source-line data-line-stdin-61" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Here is what a frequency chart with the above figures looks like:<a href="https://github.com/minborg/articles/blob/main/2024/15-StatisticsFor1brc/FrequencyName.png" rel="noopener noreferrer" style="background-color: transparent; box-sizing: border-box; font-family: -apple-system, "system-ui", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; letter-spacing: normal; text-underline-offset: 0.2rem;" target="_blank"><img alt="Frequency of Name Byte Size" src="https://github.com/minborg/articles/raw/main/2024/15-StatisticsFor1brc/FrequencyName.png" style="background-color: var(--bgColor-default, var(--color-canvas-default)); border-style: none; box-sizing: content-box; max-width: 100%;" /></a><em style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: inherit;">Chart 1, Shows the frequency of various name byte sizes.</em></p></div></div></div></div></h2><h2 style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><div dir="auto" style="background-color: #0d1117; box-sizing: border-box; color: #e6edf3; font-family: -apple-system, "system-ui", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; letter-spacing: normal; word-spacing: 0px;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;"><span style="box-sizing: border-box;"><span style="background-color: #45494a; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 1.0625rem; letter-spacing: -0.01em;">The corresponding cumulative frequency chart looks like this:</span><a href="https://github.com/minborg/articles/blob/main/2024/15-StatisticsFor1brc/CumulativeFrequencyName.png" rel="noopener noreferrer" style="background-color: transparent; box-sizing: border-box; text-underline-offset: 0.2rem;" target="_blank"><img alt="Cumulative Frequency of Name Byte Size" src="https://github.com/minborg/articles/raw/main/2024/15-StatisticsFor1brc/CumulativeFrequencyName.png" style="background-color: var(--bgColor-default, var(--color-canvas-default)); border-style: none; box-sizing: content-box; max-width: 100%;" /></a></span></p></div><div dir="auto" style="box-sizing: border-box;"><div class="sect2 has-source-line data-line-stdin-33" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-71" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><em style="box-sizing: border-box; line-height: inherit;">Chart 2, Shows the cumulative frequency of various name byte sizes.</em></p></div><div class="paragraph has-source-line data-line-stdin-73" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">As can be seen, considering only the first 16 bytes will cover more than 99% of the names in the file.</p></div></div></div></div></div></div></h2><h3 id="_appearance" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.375em; font-weight: 300; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;">Appearance</h3><h2 style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><div dir="auto" style="background-color: #0d1117; box-sizing: border-box; color: #e6edf3; font-family: -apple-system, "system-ui", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; letter-spacing: normal; word-spacing: 0px;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div class="sect2 has-source-line data-line-stdin-75" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-77" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">The number of times a station appears in the file is very similar ranging from "Roseau" with 2,417,155 to "Chihuahua" with 2,425,899 appearances.</p></div></div></div></div></div></div></h2><h3 id="_characters" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.375em; font-weight: 300; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;">Characters</h3><h2 style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><div dir="auto" style="background-color: #0d1117; box-sizing: border-box; color: #e6edf3; font-family: -apple-system, "system-ui", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; letter-spacing: normal; word-spacing: 0px;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div class="sect2 has-source-line data-line-stdin-79" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-81" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Character values can (but do not have to) be stored as <a href="https://www.asciitable.com/" style="background: none; box-sizing: border-box; color: #589df6; line-height: inherit;">ASCII-values</a>.</p></div><div class="paragraph has-source-line data-line-stdin-84" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Taking a closer look at the actual characters making up the names using binary encoded values, we can see the following:</p></div><table class="tableblock frame-all grid-all stretch has-source-line data-line-stdin-87" style="background: rgb(255, 255, 255); border-collapse: collapse; border-spacing: 0px; border: 1px solid rgb(222, 222, 222); color: #bbbbbb; margin-bottom: 1.25em; overflow-wrap: normal; width: 585px;"><colgroup style="box-sizing: border-box;"><col style="box-sizing: border-box; width: 194.664px;"></col><col style="box-sizing: border-box; width: 194.664px;"></col><col style="box-sizing: border-box; width: 194.672px;"></col></colgroup><thead style="background: rgb(98, 98, 98); box-sizing: border-box;"><tr style="box-sizing: border-box;"><th class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5em 0.625em 0.625em; text-align: left; text-rendering: optimizelegibility; vertical-align: top;">Value</th><th class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5em 0.625em 0.625em; text-align: left; text-rendering: optimizelegibility; vertical-align: top;">Char</th><th class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5em 0.625em 0.625em; text-align: left; text-rendering: optimizelegibility; vertical-align: top;">Frequency</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0..32</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">32</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">[space]</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">181605826</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">33</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">34</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">35</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">36</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">37</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">38</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">39</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">'</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">12104970</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">40</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">(</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2422734</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">41</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">)</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2422734</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">42</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">*</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">43</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">+</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">44</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">,</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4845007</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">45</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">-</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">14533546</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">46</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">.</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">9686377</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">47</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">/</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">48</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">49</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">1</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">50</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">51</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">3</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">52</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">53</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">5</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">54</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">6</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">55</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">7</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">56</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">8</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">57</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">9</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">58</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">59</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">60</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">61</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">62</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">63</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">64</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">65</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">A</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">82,312,102</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">66</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">B</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">99,268,251</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">67</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">C</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">94,430,447</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">68</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">D</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">70,215,892</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">69</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">E</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">14,526,993</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">70</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">F</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">16,957,547</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">71</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">G</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">33,899,137</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">72</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">H</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">50,855,379</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">73</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">I</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">12,102,959</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">74</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">J</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">26,634,842</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">75</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">K</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">53,262,607</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">76</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">L</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">72,646,247</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">77</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">M</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">99,292,126</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">78</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">N</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">55,695,661</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">79</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">O</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">31,475,791</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">80</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">P</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">79,892,902</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">81</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">Q</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">82</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">R</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">29,051,519</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">83</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">S</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">99,282,847</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">84</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">T</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">72,636,263</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">85</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">U</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4,842,032</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">86</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">V</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">33,897,984</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">87</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">W</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">21,796,354</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">88</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">X</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2,421,477</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">89</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">Y</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">19,373,396</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">90</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">Z</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">7,262,683</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">91</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">[</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">92</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">[back slash]</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">93</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">]</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">94</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">^</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">95</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">_</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">96</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">`</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">97</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">a</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">1,125,887,562</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">98</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">b</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">147,711,179</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">99</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">c</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">106,528,787</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">100</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">d</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">130,753,955</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">101</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">e</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">438,247,893</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">102</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">f</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">16,946,953</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">103</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">g</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">191,298,907</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">104</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">h</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">200,950,920</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">105</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">i</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">547,230,962</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">106</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">j</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">38,740,836</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">107</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">k</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">157,372,493</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">108</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">l</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">314,764,906</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">109</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">m</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">154,957,248</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">110</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">n</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">559,330,103</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">111</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">o</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">535,145,324</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">112</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">p</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">77,480,229</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">113</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">q</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">12,101,467</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">114</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">r</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">411,634,242</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">115</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">s</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">336,573,182</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">116</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">t</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">317,179,382</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">117</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">u</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">334,155,534</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">118</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">v</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">72,645,180</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">119</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">w</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">43,579,677</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">120</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">x</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">19,362,397</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">121</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">y</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">92,009,532</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">122</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">z</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">43,584,786</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">123</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">{</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">124</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">[bar]</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">125</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">}</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">126</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">~</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">127</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">[del]</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">128</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">129</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">130</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4842294</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">131</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2422260</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">132..152</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">153</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2422260</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">154</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">155</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">156</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2420126</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">157</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">158</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">159</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">160</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">161</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">162</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">163</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">164</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">165</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">166</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">167</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">168</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4843781</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">169</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">29054839</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">170</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">171</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">172</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">173</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2422053</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">174</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">175</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">176</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2421256</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">177</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">178</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">179</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">180</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">181</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">182</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">183</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">184</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2421983</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">185</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">186</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">187</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">188</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4840135</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">189</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">190</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">191</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">192</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">193</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">194</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">195</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">46002917</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">196</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4843516</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">197</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">4842294</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">198</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">199</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">200</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">2422260</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">201…256</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">0</p></td></tr></tbody></table><div class="paragraph has-source-line data-line-stdin-244" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Just considering characters a..z and not considering casing, we get the following table:</p></div><table class="tableblock frame-all grid-all stretch has-source-line data-line-stdin-247" style="background: rgb(255, 255, 255); border-collapse: collapse; border-spacing: 0px; border: 1px solid rgb(222, 222, 222); color: #bbbbbb; margin-bottom: 1.25em; overflow-wrap: normal; width: 585px;"><colgroup style="box-sizing: border-box;"><col style="box-sizing: border-box; width: 292px;"></col><col style="box-sizing: border-box; width: 292px;"></col></colgroup><thead style="background: rgb(98, 98, 98); box-sizing: border-box;"><tr style="box-sizing: border-box;"><th class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5em 0.625em 0.625em; text-align: left; text-rendering: optimizelegibility; vertical-align: top;">Char</th><th class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5em 0.625em 0.625em; text-align: left; text-rendering: optimizelegibility; vertical-align: top;">Frequency</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">a</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">1,208,199,664</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">b</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">246,979,430</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">c</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">200,959,234</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">d</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">200,969,847</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">e</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">452,774,886</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">f</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">33,904,500</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">g</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">225,198,044</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">h</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">251,806,299</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">i</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">559,333,921</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">j</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">65,375,678</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">k</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">210,635,100</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">l</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">387,411,153</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">m</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">254,249,374</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">n</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">615,025,764</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">o</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">566,621,115</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">p</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">157,373,131</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">q</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">12,101,467</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">r</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">440,685,761</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">s</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">435,856,029</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">t</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">389,815,645</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">u</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">338,997,566</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">v</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">106,543,164</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">w</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">65,376,031</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">x</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">21,783,874</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">y</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">111,382,928</p></td></tr><tr style="background: rgb(69, 73, 74); box-sizing: border-box;"><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">z</p></td><td class="tableblock halign-left valign-top" style="border: 1px solid rgb(222, 222, 222); box-sizing: border-box; font-size: inherit; line-height: 1.6; margin: 0px; padding: 0.5625em 0.625em; vertical-align: top;"><p class="tableblock" style="box-sizing: border-box; font-size: 1em; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;">50,847,469</p></td></tr></tbody></table><div class="paragraph has-source-line data-line-stdin-278" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">Here is what a frequency chart with the above figures looks like:</p></div></div></div></div></div></div></h2><h2 style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><div dir="auto" style="background-color: #0d1117; box-sizing: border-box; color: #e6edf3; font-family: -apple-system, "system-ui", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; letter-spacing: normal; word-spacing: 0px;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;"><span style="box-sizing: border-box;"><a href="https://github.com/minborg/articles/blob/main/2024/15-StatisticsFor1brc/CharacterFrequency.png" rel="noopener noreferrer" style="background-color: transparent; box-sizing: border-box; text-underline-offset: 0.2rem;" target="_blank"><img alt="Character Frequency" src="https://github.com/minborg/articles/raw/main/2024/15-StatisticsFor1brc/CharacterFrequency.png" style="background-color: var(--bgColor-default, var(--color-canvas-default)); border-style: none; box-sizing: content-box; max-width: 100%;" /></a></span></p></div><div dir="auto" style="box-sizing: border-box;"><div class="sect1 has-source-line data-line-stdin-27" style="background-color: #45494a; border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px 0px 0.625em;"><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="sect2 has-source-line data-line-stdin-79" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-282" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><em style="box-sizing: border-box; line-height: inherit;">Chart 3, Shows a character frequency table.</em></p></div></div></div></div></div></div></div></div></h2><h2 id="_temperature_statistics" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;">Temperature Statistics</h2><h2 style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><div dir="auto" style="background-color: #0d1117; box-sizing: border-box; color: #e6edf3; font-family: -apple-system, "system-ui", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; letter-spacing: normal; word-spacing: 0px;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;"><span style="background-color: #45494a; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 1.0625rem; letter-spacing: -0.01em;">The temperatures appear in the interval [-67.3, 84.9] and have the following distribution:</span><a href="https://github.com/minborg/articles/blob/main/2024/15-StatisticsFor1brc/Temperatures.png" rel="noopener noreferrer" style="background-color: transparent; box-sizing: border-box; text-underline-offset: 0.2rem;" target="_blank"><img alt="Temperarure Distribution" src="https://github.com/minborg/articles/raw/main/2024/15-StatisticsFor1brc/Temperatures.png" style="background-color: var(--bgColor-default, var(--color-canvas-default)); border-style: none; box-sizing: content-box; max-width: 100%;" /></a></p></div></div></div></div></h2><h2 style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><div dir="auto" style="background-color: #0d1117; box-sizing: border-box; color: #e6edf3; font-family: -apple-system, "system-ui", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; letter-spacing: normal; margin-bottom: 0px !important; word-spacing: 0px;"><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div class="paragraph has-source-line data-line-stdin-291" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><em style="box-sizing: border-box; line-height: inherit;">Chart 4, shows the temperature distribution.</em></p></div><div class="paragraph has-source-line data-line-stdin-293" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;">I hope this can spark some ideas in the community. Good luck with your challenge entry!</p></div></div></div></div></h2></div>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0tag:blogger.com,1999:blog-4815481734454081491.post-34551478562985775922023-10-09T00:13:00.001-07:002023-10-09T00:13:19.637-07:00My Presentations at Devoxx BE 2023<h3 id="_presentations_at_devoxx_be_october_2023" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;"><span style="color: #444444;">Presentations at Devoxx BE October 2023</span></span></h3><div class="paragraph has-source-line data-line-stdin-16" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #444444;">I did two presentations at Devoxx and also participated in the "Ask the Java Architects" presentation.</span></span></p></div><div class="paragraph has-source-line data-line-stdin-18" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV-HJZ9HzGWaGdIvHMYX6VhREfNCe1eoDA3G7DOm6AsLRdkkeftzKcpiFi-bV_F1WK9GlEHOwhIK7zgpxPdDMFMKFYufv48_zgpHN2wDpw1IZxy0Uv35qIg9ZorB6X78wqoOVpZqfof13Bk37LvJLJWjOQezFFfvTP3mAHFaW2JiCVWnyl7-2Tj8Lg428/s1292/DevoxxBE-Architects.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1292" data-original-width="1266" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV-HJZ9HzGWaGdIvHMYX6VhREfNCe1eoDA3G7DOm6AsLRdkkeftzKcpiFi-bV_F1WK9GlEHOwhIK7zgpxPdDMFMKFYufv48_zgpHN2wDpw1IZxy0Uv35qIg9ZorB6X78wqoOVpZqfof13Bk37LvJLJWjOQezFFfvTP3mAHFaW2JiCVWnyl7-2Tj8Lg428/s320/DevoxxBE-Architects.png" width="314" /></a></div><br /><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><br /></p><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #444444;">Here are the videos of the presentations:</span></span></p></div><div class="paragraph has-source-line data-line-stdin-20" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><a href="https://youtu.be/DlTUMjg7DD0" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">Ask the Java Architects</a><span style="color: #bbbbbb;"> </span><span style="color: #444444;">By Sharat Chander, Alan Bateman, Stuart Marks, Viktor Klang, Brian Goetz, and Per Minborg</span></span></p></div><div class="paragraph has-source-line data-line-stdin-22" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><a href="https://youtu.be/T6X2Yytrzyg" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">With Java 21, Your Code Runs Even Faster But How Is That Possible?</a><span style="color: #bbbbbb;"> </span><span style="color: #444444;">By Per Minborg</span></span></p></div><div class="paragraph has-source-line data-line-stdin-24" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><a href="https://youtu.be/t8c1Q2wJOoM" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">The Panama Dojo: Black Belt Programming with Java 21 and the FFM API</a><span style="color: #bbbbbb;"> </span><span style="color: #444444;">by Per Minborg</span></span></p></div><div class="paragraph has-source-line data-line-stdin-26" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #444444;">Here is the code I used in my presentations:</span></span></p></div><div class="paragraph has-source-line data-line-stdin-28" style="box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><a href="2023/October/2-Devoxx-Performance/" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">Code: With Java 21, Your Code Runs Even Faster But How Is That Possible?</a></p></div><div class="paragraph has-source-line data-line-stdin-30" style="box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><a href="2023/October/5-Devoxx-PanamaDojo/" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">Code: The Panama Dojo: Black Belt Programming with Java 21 and the FFM API</a></p></div><p><span style="background-color: white;"><span style="color: #444444;"><span style="font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 1.0625rem; letter-spacing: -0.01em;">Thanks to all who provided feedback and those who attended the presentations. See you next year!</span> </span></span></p>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0tag:blogger.com,1999:blog-4815481734454081491.post-36286691526790138002023-09-14T03:17:00.005-07:002023-09-14T23:23:29.865-07:00Java Records are "Trusted" and Consequently Faster<p> </p><h1 style="border-bottom: 1px solid rgb(221, 221, 223); box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.75em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 0px 0px 1.25rem; padding: 1rem 0px 8px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Java Records are "Trusted" and Consequently Faster</span></h1><div id="preamble" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-3" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Did you know Java records are trusted by the Hotspot VM in a special way? This makes their speed superior in some aspects compared to regular Java classes. In this short article, we will take a look at <i>constant folding of instance fields </i>and how this can bolster the performance of your Java application.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-5" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_background" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Background</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-7" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Suppose we want to model an immutable point:</span></p></div><div class="listingblock has-source-line data-line-stdin-10" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">interface</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">Point</span> {
<span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> x();
<span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> y();
}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-17" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Before record classes <a href="https://openjdk.org/jeps/395" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; line-height: inherit;" target="_blank">were introduced</a> in Java, data classes had to be "manually" coded using a regular Java class like this:</span></p></div><div class="listingblock has-source-line data-line-stdin-20" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">class</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">RegularPoint</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">implements</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Point</span> {
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> x;
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> y;
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> RegularPoint(<span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> x, <span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> y) {
<span style="box-sizing: border-box; color: #995500;">this</span>.x = x;
<span style="box-sizing: border-box; color: #995500;">this</span>.y = y;
}
<span style="box-sizing: border-box; color: #000077;">@Override</span>
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> x() {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> x;
}
<span style="box-sizing: border-box; color: #000077;">@Override</span>
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> y() {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> y;
}
<span style="box-sizing: border-box; color: #777777;">// Implementations of toString(), hashCode() and equals()</span>
<span style="box-sizing: border-box; color: #777777;">// omitted for brevity</span>
}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-47" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">With records, it became much easier and, we also got reasonable default implementations of the methods <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">toString()</code>, <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">hashCode()</code> and <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">equals()</code>:</span></p></div><div class="listingblock has-source-line data-line-stdin-50" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> record RecordPoint(<span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> x, <span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> y) <span style="box-sizing: border-box; color: #008888; font-weight: bold;">implements</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Point</span> {}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-54" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">As an extra bonus, there is an emerging property for records that makes them eligible for constant folding optimizations if used in a static context. Read more about this in the following chapters.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-56" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_setup" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Setup</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-58" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Suppose we keep track of the unique origin point in a <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">static</code> variable like this:</span></p></div><div class="listingblock has-source-line data-line-stdin-61" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Point</span> ORIGIN = <span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RecordPoint(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">0</span>);</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-65" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Further, assume we have a method that determines if a given <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">Point</code> is at the origin point:</span></p></div><div class="listingblock has-source-line data-line-stdin-68" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">boolean</span> isOrigin(<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Point</span> point) {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> point.x() == ORIGIN.x() &&
point.y() == ORIGIN.y();
}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-75" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">We could then write a small program that demonstrates the principles:</span></p></div><div class="listingblock has-source-line data-line-stdin-78" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">class</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">Demo</span> {
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Point</span> ORIGIN = <span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RecordPoint(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">0</span>);
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">void</span> main(<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">String</span><span style="box-sizing: border-box; color: #333399; font-weight: bold;">[]</span> args) {
analyze(<span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RegularPoint(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">0</span>));
analyze(<span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RegularPoint(<span style="box-sizing: border-box; color: #0000dd;">1</span>, <span style="box-sizing: border-box; color: #0000dd;">1</span>));
}
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">void</span> analyze(<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Point</span> point) {
<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">System</span>.out.format(<span style="background-color: rgba(255, 0, 0, 0.05); box-sizing: border-box;"><span style="box-sizing: border-box; color: #771100;">"</span><span style="box-sizing: border-box; color: #dd2200;">The point %s is %s at the origin.%n</span><span style="box-sizing: border-box; color: #771100;">"</span></span>,
point, isOrigin(point) ? <span style="background-color: rgba(255, 0, 0, 0.05); box-sizing: border-box;"><span style="box-sizing: border-box; color: #771100;">"</span><span style="box-sizing: border-box; color: #771100;">"</span></span> : <span style="background-color: rgba(255, 0, 0, 0.05); box-sizing: border-box;"><span style="box-sizing: border-box; color: #771100;">"</span><span style="box-sizing: border-box; color: #dd2200;">not</span><span style="box-sizing: border-box; color: #771100;">"</span></span>);
}
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">boolean</span> isOrigin(<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Point</span> point) {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> point.x() == ORIGIN.x() &&
point.y() == ORIGIN.y();
}
}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-101" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">When run, the code above will produce the following output:</span></p></div><div class="listingblock has-source-line data-line-stdin-104" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;">The point RegularPoint{x=0, y=0} is at the origin.
The point RegularPoint{x=1, y=1} is not at the origin.</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-109" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">We could easily replace the use of <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">new RegularPoint(…)</code> with <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">new RecordPoint(…)</code> in the code above, and we would get a similar output:</span></p></div><div class="listingblock has-source-line data-line-stdin-112" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;">The point RecordPoint[x=0, y=0] is at the origin.
The point RecordPoint[x=1, y=1] is not at the origin.</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-117" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">It appears the two implementation variants of the interface <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">Point</code> work as expected. But how is the performance of code affected by switching from regular Java classes to records?</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-119" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_benchmarks" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Benchmarks</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-121" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Here is a benchmark that can be used to measure the effects of using records over regular classes:</span></p></div><div class="listingblock has-source-line data-line-stdin-124" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #000077;">@BenchmarkMode</span>(Mode.AverageTime)
<span style="box-sizing: border-box; color: #000077;">@OutputTimeUnit</span>(<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">TimeUnit</span>.NANOSECONDS)
<span style="box-sizing: border-box; color: #000077;">@State</span>(Scope.Benchmark)
<span style="box-sizing: border-box; color: #000077;">@Warmup</span>(iterations = <span style="box-sizing: border-box; color: #0000dd;">5</span>, time = <span style="box-sizing: border-box; color: #0000dd;">1</span>)
<span style="box-sizing: border-box; color: #000077;">@Measurement</span>(iterations = <span style="box-sizing: border-box; color: #0000dd;">5</span>, time = <span style="box-sizing: border-box; color: #0000dd;">1</span>)
<span style="box-sizing: border-box; color: #000077;">@Fork</span>(value=<span style="box-sizing: border-box; color: #0000dd;">3</span>)
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">class</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">Bench</span> {
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> RegularPoint REGULAR_ORIGIN = <span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RegularPoint(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">0</span>);
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> RecordPoint RECORD_ORIGIN = <span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RecordPoint(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">0</span>);
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">List</span><RegularPoint> regularPoints;
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">List</span><RecordPoint> recordPoints;
<span style="box-sizing: border-box; color: #000077;">@Setup</span>
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">void</span> setup() {
regularPoints = IntStream.range(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">16</span>)
.mapToObj(i -> <span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RegularPoint(i, i))
.toList();
recordPoints = IntStream.range(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">16</span>)
.mapToObj(i -> <span style="box-sizing: border-box; color: #008800; font-weight: bold;">new</span> RecordPoint(i, i))
.toList();
}
<span style="box-sizing: border-box; color: #000077;">@Benchmark</span>
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">void</span> regular(Blackhole bh) {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">for</span> (RegularPoint point: regularPoints) {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">if</span> (point.x() == REGULAR_ORIGIN.x() && point.y() == REGULAR_ORIGIN.y()) {
bh.consume(<span style="box-sizing: border-box; color: #0000dd;">1</span>);
} <span style="box-sizing: border-box; color: #008800; font-weight: bold;">else</span> {
bh.consume(<span style="box-sizing: border-box; color: #0000dd;">0</span>);
}
}
}
<span style="box-sizing: border-box; color: #000077;">@Benchmark</span>
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">void</span> record(Blackhole bh) {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">for</span> (RecordPoint point: recordPoints) {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">if</span> (point.x() == RECORD_ORIGIN.x() && point.y() == RECORD_ORIGIN.y()) {
bh.consume(<span style="box-sizing: border-box; color: #0000dd;">1</span>);
} <span style="box-sizing: border-box; color: #008800; font-weight: bold;">else</span> {
bh.consume(<span style="box-sizing: border-box; color: #0000dd;">0</span>);
}
}
}
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">void</span> main(<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">String</span><span style="box-sizing: border-box; color: #333399; font-weight: bold;">[]</span> args) <span style="box-sizing: border-box; color: #008888; font-weight: bold;">throws</span> <span style="box-sizing: border-box; color: #cc0000; font-weight: bold;">Exception</span> {
org.openjdk.jmh.Main.main(args);
}
}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-179" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">When run on a Mac M1 laptop, the following results emerged (lower is better):</span></p></div><div class="listingblock has-source-line data-line-stdin-182" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;">Benchmark Mode Cnt Score Error Units
Bench.regular avgt 15 10.424 ± 0.257 ns/op
Bench.record avgt 15 9.412 ± 0.181 ns/op</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-188" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">As can be seen, records are about 10% faster than regular classes in this benchmark.</span></p></div><div class="paragraph has-source-line data-line-stdin-190" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Here is what it looks like in a graph:</span></p><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhppZR0mNazCeVTbJGN83S_wPbnEYaxj-h9a0QkhpJ88dahk7IzyGOg99AC8eG7inHkbfT8jnjzrzBbanEN8wK31OvN_aV87jn3cAxQcO5e5KtLMC2GVkJBpUjVmnPtGd3LXoFxvAUMSV9wTKW7JHw1IIA-h-WceqkwrMERBM0OLQCxijJ0KQF-WmdbKKg/s1658/TrustedRecordChart.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1022" data-original-width="1658" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhppZR0mNazCeVTbJGN83S_wPbnEYaxj-h9a0QkhpJ88dahk7IzyGOg99AC8eG7inHkbfT8jnjzrzBbanEN8wK31OvN_aV87jn3cAxQcO5e5KtLMC2GVkJBpUjVmnPtGd3LXoFxvAUMSV9wTKW7JHw1IIA-h-WceqkwrMERBM0OLQCxijJ0KQF-WmdbKKg/w640-h394/TrustedRecordChart.png" width="640" /></a></div><em style="background-color: white; box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: inherit;">Graph 1, shows the performance of regular and record classes.</em><p></p></div></div></div><div class="sect1 has-source-line data-line-stdin-196" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_under_the_hood" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Under the Hood</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-198" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Looking at why records can be faster in cases like the above, there is a clue in the class <a href="https://github.com/openjdk/jdk/blob/edd454b502b9bacde55492820e52655bbac63b89/src/hotspot/share/ci/ciField.cpp#L239-L241" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; line-height: inherit;" target="_blank">ciField.cpp</a> which tells the Hotspot compiler which instance fields should be "trusted" when performing constant folding. The class also gives away some clues about other Java classes that benefit from the same optimizations. One example is the <a href="https://openjdk.org/jeps/454" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; line-height: inherit;" target="_blank">Foreign Function & Memory API</a> that is slated to be finalized in Java 22 and where, for example, all classes implementing the various <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">MemoryLayout</code> variants all are eligible for constant folding optimizations.</span></p></div><div class="paragraph has-source-line data-line-stdin-200" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">The C++ class above is not available to regular Java programs but, by switching to records, we may directly reap the benefits of constant folding for instance fields.</span></p></div><div class="paragraph has-source-line data-line-stdin-202" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">As a final note, it should be said that modifying records fields (which are <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">private</code> and <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">final</code>) using, for example, <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">Unsafe</code> is … well … unsafe and would produce an undefined result. Don’t do that!<br /><br />UPDATE:<br /><span style="font-family: "DejaVu Sans Mono", monospace; font-size: 15.9375px; letter-spacing: normal; word-spacing: -2.39062px;">Unsafe</span> and reflection provide special protection against tampering with records making it very difficult to update record fields via backdoors. For example, trying to obtain the field offset for a record component via </span><span style="background-color: white; font-family: "DejaVu Sans Mono", monospace; font-size: 15.9375px; word-spacing: -2.39062px;">Unsafe </span><span style="background-color: white; font-size: 1.0625rem; letter-spacing: -0.01em;">will result in an </span><span style="font-family: "DejaVu Sans Mono", monospace; font-size: 15.9375px; letter-spacing: normal; word-spacing: -2.39062px;">UnsupportedOperationExcption</span><span style="background-color: white; font-size: 1.0625rem; letter-spacing: -0.01em;"> being thrown.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-204" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><h2 id="_conclusion" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Conclusion</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-206" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Records offer a convenient way of expressing data carriers. As an added benefit, they also provide improved performance compared to regular Java classes in some applications.</span></p></div></div></div>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Sweden60.128161000000013 18.64350131.817927163821167 -16.512749 88.438394836178858 53.799751tag:blogger.com,1999:blog-4815481734454081491.post-84491973911583736322023-08-28T08:06:00.006-07:002023-08-28T09:24:50.447-07:00Java 22: Panama FFM Provides Massive Performance Improvements for Native Strings<p> </p><h1 style="border-bottom: 1px solid rgb(221, 221, 223); box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.75em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 0px 0px 1.25rem; padding: 1rem 0px 8px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">Java 22: Panama FFM Provides Massive Performance Improvements for Native Strings</span></h1><div id="preamble" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-3" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">The Panama Foreign Function and Memory (FFM) API is slated to be finalized in Java 22 and will then be a part of the public Java API. One thing that is perhaps less known is the significant performance improvements made by FFM in certain areas in 22. In this short article, we will be looking at <em style="box-sizing: border-box; line-height: inherit;">benchmarking string conversion</em> in FFM for Java 21 and Java 22 compared to using old JNI calls.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-5" style="box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_c_and_java_strings" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">C and Java Strings</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-7" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">The Java Native Interface (JNI) has been used historically as a means to bridge Java to native calls before FFM was available. Both schemes entail converting strings back and forth between C and Java String data structures. As you might remember, C strings are just a bunch of bytes that are zero-terminated whereas Java Strings use a backing array with a known length.</span></p></div><div class="paragraph has-source-line data-line-stdin-9" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">When calling native function that takes one or more strings and/or returns a string (both are relatively common), the performance of converting strings back and forth becomes important.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-11" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_benchmarks" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">Benchmarks</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-13" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #666666;">We have run some string benchmarks (see</span><span style="color: #bbbbbb;"> </span><a href="https://github.com/openjdk/panama-foreign/pull/874/files" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">the source code here</a><span style="color: #666666;">) on a AMD Ryzen 9 3900X 12-Core Processor machine and preliminary results indicate blistering performance for FFM string conversion in Java 22:</span></span></p></div><div class="listingblock has-source-line data-line-stdin-16" style="background-color: #45494a; box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;">Benchmark (size) Mode Cnt Score Error Units
ToJavaStringTest.jni_readString 5 avgt 30 86.520 ? 1.842 ns/op
ToJavaStringTest.jni_readString 20 avgt 30 97.151 ? 1.459 ns/op
ToJavaStringTest.jni_readString 100 avgt 30 143.853 ? 1.287 ns/op
ToJavaStringTest.jni_readString 200 avgt 30 189.867 ? 2.337 ns/op
ToJavaStringTest.panama_readString 5 avgt 30 21.380 ? 0.351 ns/op
ToJavaStringTest.panama_readString 20 avgt 30 36.250 ? 0.520 ns/op
ToJavaStringTest.panama_readString 100 avgt 30 43.368 ? 0.544 ns/op
ToJavaStringTest.panama_readString 200 avgt 30 53.442 ? 2.048 ns/op
Benchmark (size) Mode Cnt Score Error Units
ToCStringTest.jni_writeString 5 avgt 30 47.450 ? 0.832 ns/op
ToCStringTest.jni_writeString 20 avgt 30 56.208 ? 0.422 ns/op
ToCStringTest.jni_writeString 100 avgt 30 108.341 ? 0.459 ns/op
ToCStringTest.jni_writeString 200 avgt 30 157.119 ? 1.669 ns/op
ToCStringTest.panama_writeString 5 avgt 30 45.361 ? 0.717 ns/op
ToCStringTest.panama_writeString 20 avgt 30 47.742 ? 0.554 ns/op
ToCStringTest.panama_writeString 100 avgt 30 47.580 ? 0.673 ns/op
ToCStringTest.panama_writeString 200 avgt 30 49.060 ? 0.694 ns/op</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-39" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #666666;">Needless to say, the </span><code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ToJavaStringTest</code><span style="color: #bbbbbb;"> </span><span style="color: #666666;">runs are converting a C string to a Java string whereas the</span><span style="color: #bbbbbb;"> </span><code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ToCStringTest</code><span style="color: #bbbbbb;"> </span><span style="color: #666666;">runs convert a Java string to a C string. The </span><code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">size</code><span style="color: #bbbbbb;"> </span><span style="color: #666666;">indicates the number of bytes of the original string. Java strings were coded in UTF-8.</span></span></p></div><div class="paragraph has-source-line data-line-stdin-41" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #666666;">As can be seen, we can expect FFM to convert C strings to Java strings more than</span><span style="color: #bbbbbb;"> </span><strong style="box-sizing: border-box; letter-spacing: -0.005em; line-height: inherit;">three times faster with FFM in Java 22</strong>.<span style="color: #bbbbbb;"> </span><span style="color: #666666;">In the other direction, performance will be about the same for small strings but for larger strings (where it matters more), the speedup factor will be ever-increasing. For example, for strings of length 200, the speedup factor is more than three times.</span></span></p></div><div class="dlist has-source-line data-line-stdin-43" style="box-sizing: border-box; margin: 0px; padding: 0px;"><dl style="box-sizing: border-box; font-family: inherit; line-height: 1.6; list-style-position: outside; margin: 0px 0px 1.25em; padding: 0px;"><dt class="hdlist1" style="box-sizing: border-box; font-size: 1.0625rem; font-weight: bold; margin: 0px 0px 0.3125em; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Note</span></dt><dd style="box-sizing: border-box; margin: 0px 0px 0px 1.125em; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #666666;">It should be noted that the benchmarks are not purely about string conversion as a JNI call also incurs a small state transition penalty for each call. The Java to C string performs a memory allocation (for the string bytes). While this could be avoided, it was included in the benchmark as that is what happens with JNI’s </span><code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">GetStringUTFChars</code><span style="color: #bbbbbb;">.</span></span></p></dd></dl></div></div></div><div class="sect1 has-source-line data-line-stdin-45" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_diagrams" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">Diagrams</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-47" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">Here are two diagrams outlining the performance benefits of FFM in comparison with JNI. The diagram also includes FFM in Java 21 to highlight the recent performance improvements made in 22 (Lower is Better):</span></p></div><div class="imageblock has-source-line data-line-stdin-49" style="box-sizing: border-box; color: #bbbbbb; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh26KHByOyTeitm-BBUCRMJunRKNxI16XWe7OpYBnubaP0VOVyyXJXHeC3QX8kT273iAQdQ1XEMnjcLnazrvM2XABzIONri365yXcdTE8QIZOeND-D5QXkJZtPm8DrM1CxKDGWhPp7_5fFxivJEiYxH9rd60B6F_jqfJA_IkyE7dV5B-P9uqalGVNPKIq4/s1280/C-to-Java.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="790" data-original-width="1280" height="397" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh26KHByOyTeitm-BBUCRMJunRKNxI16XWe7OpYBnubaP0VOVyyXJXHeC3QX8kT273iAQdQ1XEMnjcLnazrvM2XABzIONri365yXcdTE8QIZOeND-D5QXkJZtPm8DrM1CxKDGWhPp7_5fFxivJEiYxH9rd60B6F_jqfJA_IkyE7dV5B-P9uqalGVNPKIq4/w640-h397/C-to-Java.png" width="640" /></a></div><br /><span style="background-color: white;"><br /></span></div></div><div class="paragraph has-source-line data-line-stdin-50" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><em style="background-color: white; box-sizing: border-box; line-height: inherit;"><span style="color: #666666;">Diagram 1, shows the performance of converting a C string to a Java String.</span></em></p></div><div class="imageblock has-source-line data-line-stdin-52" style="box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6qBMCA8H_V8PCWIKuMeHTalkYeWCM3LKUJ1am2PkcXKjkHecDIFyZql-duwdLIqLcsBHs8OYtoalxEHmGHe_WrU4CyZF0U1wgn6_t4Sp-TENJu7xpwj1YI9q2263hI3PwobOub4H0JkrMQMfE5DzEoiKeNsWrW2BJekgJph6NLdKIkYxpPyXg1NYTkBo/s1266/Java-to-C.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="788" data-original-width="1266" height="398" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6qBMCA8H_V8PCWIKuMeHTalkYeWCM3LKUJ1am2PkcXKjkHecDIFyZql-duwdLIqLcsBHs8OYtoalxEHmGHe_WrU4CyZF0U1wgn6_t4Sp-TENJu7xpwj1YI9q2263hI3PwobOub4H0JkrMQMfE5DzEoiKeNsWrW2BJekgJph6NLdKIkYxpPyXg1NYTkBo/w640-h398/Java-to-C.png" width="640" /></a></div><br /><div class="content" style="box-sizing: border-box; color: #bbbbbb; margin: 0px; padding: 0px;"><br /></div></div><div class="paragraph has-source-line data-line-stdin-53" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><em style="background-color: white; box-sizing: border-box; line-height: inherit;"><span style="color: #666666;">Diagram 2, shows the performance of converting a Java string to a C String.</span></em></p></div></div></div><div class="sect1 has-source-line data-line-stdin-55" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_future_improvements" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">Future Improvements</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-57" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">FFM allows us to use custom allocators and so, if we make several calls, we can reuse memory segments thereby improving performance further. This is not possible with JNI.</span></p></div><div class="paragraph has-source-line data-line-stdin-59" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">It is also possible that we will see even better FFM performance in future Java versions once the Vector API becomes a final feature.</span></p></div><div class="sect2 has-source-line data-line-stdin-61" style="box-sizing: border-box; margin: 0px; padding: 0px;"><h3 id="_jdk_early_access_builds" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 1.6875em; font-weight: 300; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">JDK Early-Access Builds</span></h3><div class="paragraph has-source-line data-line-stdin-63" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">Run your own code on an early access JDK today by downloading a <a href="https://jdk.java.net" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; line-height: inherit;">JDK Early-Access Build</a>.</span></p></div><div class="dlist has-source-line data-line-stdin-65" style="box-sizing: border-box; margin: 0px; padding: 0px;"><dl style="box-sizing: border-box; font-family: inherit; line-height: 1.6; list-style-position: outside; margin: 0px 0px 1.25em; padding: 0px;"><dt class="hdlist1" style="box-sizing: border-box; font-size: 1.0625rem; font-weight: bold; margin: 0px 0px 0.3125em; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Note</span></dt><dd style="box-sizing: border-box; margin: 0px 0px 0px 1.125em; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #666666;">At the time of writing this article, the performance improvements are not merged in the Java 22 mainline yet. You can however build your own snapshot version with the performance improvements mentioned above by clonin</span><span style="color: #bbbbbb;">g </span><a href="https://github.com/openjdk/panama-foreign" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">github.com/openjdk/panama-foreign</a></span></p></dd></dl></div></div></div></div><div class="sect1 has-source-line data-line-stdin-67" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_resources" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">Resources</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="ulist has-source-line data-line-stdin-69" style="box-sizing: border-box; margin: 0px; padding: 0px;"><ul style="box-sizing: border-box; font-family: inherit; line-height: 1.6; list-style-position: outside; margin: 0px 0px 1.25em 1.5em; padding: 0px;"><li class="has-source-line data-line-stdin-69" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 0.625em; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><a href="https://openjdk.org/jeps/434" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">JEP 442</a> Foreign Function & Memory API (Third Preview)</span></p></li><li class="has-source-line data-line-stdin-70" style="box-sizing: border-box; color: #bbbbbb; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 0.625em; padding: 0px; text-rendering: optimizelegibility;"><a href="https://openjdk.org/jeps/8310626" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: none white; box-sizing: border-box; color: #589df6; line-height: inherit;">JEP draft: Foreign Function & Memory API (Final)</a></p></li><li class="has-source-line data-line-stdin-71" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 0.625em; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;"><span style="color: #666666;">Open-Source Panama FFM on GitHub:</span><span style="color: #bbbbbb;"> </span><a href="https://github.com/openjdk/panama-foreign" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">github.com/openjdk/panama-foreign</a></span></p></li></ul></div></div></div><div class="sect1 has-source-line data-line-stdin-73" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><h2 id="_acknowledgments" style="box-sizing: border-box; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white; color: #666666;">Acknowledgments</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-75" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white; color: #666666;">This article was written by me (Per Minborg) and Maurizio Cimadamore.</span></p></div></div></div>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Sweden60.128161000000013 18.64350131.817927163821167 -16.512749 88.438394836178858 53.799751tag:blogger.com,1999:blog-4815481734454081491.post-77822254413826405622023-08-02T23:51:00.005-07:002023-08-04T03:52:47.071-07:00Java: New Draft JEP: "Computed Constants"<h1 style="border-bottom: 1px solid rgb(221, 221, 223); box-sizing: border-box; color: #bbbbbb; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.75em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 0px 0px 1.25rem; padding: 1rem 0px 8px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Java: JEP Draft: "Computed Constants"</span></h1><div id="preamble" style="box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-3" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">We finally made the draft <a href="https://openjdk.org/jeps/8312611" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">JEP "Computed Constants"</a> public and I can’t wait to tell you more about it! <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> objects are superfast immutable value holders that can be initialized independently of when they are created. As an added benefit, these objects may in the future be even more optimized via <a href="https://openjdk.org/projects/leyden/notes/03-toward-condensers" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">"condensers"</a> that eventually might become available through project <a href="https://openjdk.org/projects/leyden/" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">Leyden</a>.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-5" style="box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_background" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Background</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-7" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Oftentimes, we use <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">static</code> fields to hold objects that are only initialized once:</span></p></div><div class="listingblock has-source-line data-line-stdin-10" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #777777;">// ordinary static initialization</span>
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span> LOGGER = <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span>.getLogger(<span style="background-color: rgba(255, 0, 0, 0.05); box-sizing: border-box;"><span style="box-sizing: border-box; color: #771100;">"</span><span style="box-sizing: border-box; color: #dd2200;">com.foo.Bar</span><span style="box-sizing: border-box; color: #771100;">"</span></span>);
...
LOGGER.log(...);</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-18" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">The <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">LOGGER</code> variable will be unconditionally initialized as soon as the class where it is declared is loaded (loading occurs upon the class being first referenced).</span></p></div><div class="paragraph has-source-line data-line-stdin-20" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">One way to prevent all static fields in a class from being initialized at the same time is to use the <a href="https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">class holder idiom</a> allowing us to defer initialization until we actually need the variable:</span></p></div><div class="listingblock has-source-line data-line-stdin-23" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #777777;">// Initialization-on-demand holder idiom</span>
<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span> logger() {
<span style="box-sizing: border-box; color: #333399; font-weight: bold;">class</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">Holder</span> {
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span> LOGGER = <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span>.getLogger(<span style="background-color: rgba(255, 0, 0, 0.05); box-sizing: border-box;"><span style="box-sizing: border-box; color: #771100;">"</span><span style="box-sizing: border-box; color: #dd2200;">com.foo.Bar</span><span style="box-sizing: border-box; color: #771100;">"</span></span>);
}
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> Holder.LOGGER;
}
...
logger().log(...);</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-35" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">While this works well in theory, there are significant drawbacks: </span></p><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"></p><ul style="text-align: left;"><li><span style="background-color: white;">Each constant that needs to be decoupled would need <em style="box-sizing: border-box; line-height: inherit;">its own</em> holding class (adding static footprint overhead) </span></li><li><span style="background-color: white;">Only works if the decoupled constants are independent </span></li><li><span style="background-color: white;">Does only work for <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">static</code> variables and not for instance variables and objects</span></li></ul><p></p></div><div class="paragraph has-source-line data-line-stdin-40" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Another way is to use the <a href="https://en.wikipedia.org/wiki/Double-checked_locking" style="background-attachment: initial; background-clip: initial; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #589df6; line-height: inherit;">double-checked locking idiom</a> that can also be used for deferring initialization. This works for both <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">static</code> variables, instance variables and objects:</span></p></div><div class="listingblock has-source-line data-line-stdin-43" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #777777;">// Double-checked locking idiom</span>
<span style="box-sizing: border-box; color: #333399; font-weight: bold;">class</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">Foo</span> {
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">volatile</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span> logger;
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">public</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span> logger() {
<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span> v = logger;
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">if</span> (v == <span style="box-sizing: border-box; color: #006699;">null</span>) {
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">synchronized</span> (<span style="box-sizing: border-box; color: #995500;">this</span>) {
v = logger;
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">if</span> (v == <span style="box-sizing: border-box; color: #006699;">null</span>) {
logger = v = <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span>.getLogger(<span style="background-color: rgba(255, 0, 0, 0.05); box-sizing: border-box;"><span style="box-sizing: border-box; color: #771100;">"</span><span style="box-sizing: border-box; color: #dd2200;">com.foo.Bar</span><span style="box-sizing: border-box; color: #771100;">"</span></span>);
}
}
}
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> v;
}
}
...
foo.logger().log(...);</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-66" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">There is no way for the (current) JVM to determine that the <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">logger</code> is <em style="box-sizing: border-box; line-height: inherit;">monotonic</em> in the sense that it can only change from <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">null</code> to a value <em style="box-sizing: border-box; line-height: inherit;">once</em> and then will always remain. So, the JVM is unable to apply constant folding and other optimizations. Also, because <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">logger</code> needs to be declared <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">volatile</code> there is a small performance penalty paid for each access.</span></p></div><div class="paragraph has-source-line data-line-stdin-68" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">The <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> class comes to the rescue here and offers the best of two worlds: Flexible initialization and good performance!</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-70" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_computed_constant" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Computed Constant</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-72" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Here is how <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> can be used with the logger example:</span></p></div><div class="listingblock has-source-line data-line-stdin-75" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #333399; font-weight: bold;">class</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">Bar</span> {
<span style="box-sizing: border-box; color: #777777;">// 1. Declare a computed constant value</span>
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">private</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> ComputedConstant<<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span>> LOGGER =
ComputedConstant.of( () -> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span>.getLogger(<span style="background-color: rgba(255, 0, 0, 0.05); box-sizing: border-box;"><span style="box-sizing: border-box; color: #771100;">"</span><span style="box-sizing: border-box; color: #dd2200;">com.foo.Bar</span><span style="box-sizing: border-box; color: #771100;">"</span></span>) );
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Logger</span> logger() {
<span style="box-sizing: border-box; color: #777777;">// 2. Access the computed value</span>
<span style="box-sizing: border-box; color: #777777;">// (evaluation made before the first access)</span>
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> LOGGER.get();
}
}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-89" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">This is similar in spirit to the class-holder idiom, and offers the same performance, constant-folding, and thread-safety characteristics, but is simpler and incurs a lower static footprint since no additional class is required.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-91" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_benchmarks" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Benchmarks</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-93" style="box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">I’ve run some benchmarks on my Mac Pro M1 ARM-based machine and preliminary results indicates excellent performance for <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">static</code> <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> fields:</span></p></div><div class="listingblock has-source-line data-line-stdin-96" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; line-height: inherit;"><span><b>Benchmark Mode Cnt Score Error Units</b>
staticHolder avgt 15 0.561 ? 0.002 ns/op
doubleChecked avgt 15 1.122 ? 0.003 ns/op
constant avgt 15 0.563 ? 0.002 ns/op // static ComputedConstant</span></code></pre></div></div><div class="paragraph has-source-line data-line-stdin-103" style="box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">As can be seen, a <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> has the same performance as the static holder (but with no extra class footprint) and much better performance than a double-checked locking variable.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-105" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_collections_of_computedconstant" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Collections of ComputedConstant</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-107" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">So far so good. However, the hidden gem in the JEP is the ability to obtain Collections of <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> elements. This is achieved using a factory method that provides not a single <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> (with its provider) but a whole <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">List</code> of <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> elements that is handled by a single providing mapper that can initialize all the elements in the list. This allows a large number of variables to be handled via a <em style="box-sizing: border-box; line-height: inherit;">single</em> list, thereby saving space compared to having many single constants and initialization lambdas (for example).</span></p></div><div class="paragraph has-source-line data-line-stdin-109" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Like a <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant<V></code> variable, a <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">List<ComputedConstant<V>></code> variable is created by providing an element mapper - typically in the form of a lambda expression, which is used to compute the value associated with the i-th element of the <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">List</code> when the element value is first accessed:</span></p></div><div class="listingblock has-source-line data-line-stdin-112" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="java" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"><span style="box-sizing: border-box; color: #333399; font-weight: bold;">class</span> <span style="box-sizing: border-box; color: #bb0066; font-weight: bold;">Fibonacci</span> {
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #008888; font-weight: bold;">final</span> <span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">List</span><ComputedConstant<<span style="box-sizing: border-box; color: #00aa88; font-weight: bold;">Integer</span>>> FIBONACCI =
ComputedConstant.of(<span style="box-sizing: border-box; color: #0000dd;">1</span>_000, Fibonacci::fib);
<span style="box-sizing: border-box; color: #008888; font-weight: bold;">static</span> <span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> fib(<span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span> n) {
<span style="box-sizing: border-box; color: #008800; font-weight: bold;">return</span> (n < <span style="box-sizing: border-box; color: #0000dd;">2</span>)
? n
: FIBONACCI.get(n - <span style="box-sizing: border-box; color: #0000dd;">1</span>) + FIBONACCI.get(n - <span style="box-sizing: border-box; color: #0000dd;">2</span>);
}
<span style="box-sizing: border-box; color: #333399; font-weight: bold;">int</span><span style="box-sizing: border-box; color: #333399; font-weight: bold;">[]</span> fibs = IntStream.range(<span style="box-sizing: border-box; color: #0000dd;">0</span>, <span style="box-sizing: border-box; color: #0000dd;">10</span>)
.map(Fibonacci::fib)
.toArray(); <span style="box-sizing: border-box; color: #777777;">// { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 }</span>
}</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-130" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Note how there’s only one field of type <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">List<ComputedConstant<Integer>></code> to initialize - every other computation is performed on-demand when the corresponding element of the List <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">FIBONACCI</code> is accessed.</span></p></div><div class="paragraph has-source-line data-line-stdin-132" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">When a computation depends on more sub-computations, it induces a dependency graph, where each computation is a node in the graph, and has zero or more edges to each of the sub-computation nodes it depends on. For instance, the dependency graph associated with <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">fib(5)</code> is given below:</span></p></div><div class="listingblock has-source-line data-line-stdin-135" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; font-size: 0.90625em; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; font-size: inherit; line-height: inherit;"> ___________fib(5)___________
/ \
____fib(4)____ ____fib(3)____
/ \ / \
fib(3) fib(2) fib(2) fib(1)
/ \ / \ / \
fib(2) fib(1) fib(1) fib(0) fib(1) fib(0)</code></pre></div></div><div class="paragraph has-source-line data-line-stdin-145" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">The Computed Constant API allows modeling this cleanly, while still preserving good constant-folding guarantees and integrity of updates in the case of multi-threaded access.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-147" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_benchmarks_collections" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Benchmarks Collections</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-149" style="box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">These benchmarks were run on the same platform as above and show collections of <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> elements enjoy the same performance benefits as the single ones do:</span></p></div><div class="listingblock has-source-line data-line-stdin-152" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; line-height: inherit;"><span><b>Benchmark Mode Cnt Score Error Units</b>
staticHolder avgt 15 0.570 ? 0.005 ns/op // int[] in a holder class
doubleChecked avgt 15 1.124 ? 0.044 ns/op
constant avgt 15 0.562 ? 0.005 ns/op // List<ComputedConstant></span></code></pre></div></div><div class="paragraph has-source-line data-line-stdin-159" style="box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">Again, the <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> clocks in at native static array speed while providing much better flexibility as to when initialized.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-161" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_instance_performance" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Instance Performance</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-163" style="box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">The performance for instance variables and objects is superior to holders using the double-checked idiom showed above as can be seen in the benchmarks below:</span></p></div><div class="listingblock has-source-line data-line-stdin-166" style="background-color: #45494a; box-sizing: border-box; margin: 0px 0px 1.25em; padding: 0px;"><div class="content" style="box-sizing: border-box; margin: 0px; padding: 0px; position: relative;"><pre class="CodeRay highlight" style="background: rgb(247, 247, 248); border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); filter: invert(90%) hue-rotate(180deg); font-family: "DejaVu Sans Mono", monospace; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 1em; text-rendering: optimizespeed; text-wrap: wrap;"><code data-lang="text" style="box-sizing: border-box; color: inherit; display: block; font-family: "DejaVu Sans Mono", monospace; line-height: inherit;"><span><b>Benchmark Mode Cnt Score Error Units</b>
doubleChecked avgt 15 1.259 ? 0.023 ns/op
constant avgt 15 0.728 ? 0.022 ns/op // ComputedConstant</span></code></pre></div></div><div class="paragraph has-source-line data-line-stdin-172" style="box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">So, <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> is more than 40% faster than the double-checked holder class tested on my machine.<br /><br />Note: Instance performance is subject to review.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-174" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_where_is_it" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Where is it?</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="paragraph has-source-line data-line-stdin-176" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 1.25rem; padding: 0px; text-rendering: optimizelegibility;"><span style="background-color: white;">At the time of writing this article, <code style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 4px; box-sizing: border-box; color: rgba(0, 0, 0, 0.9); font-family: "DejaVu Sans Mono", monospace; font-size: 0.9375em; letter-spacing: 0px; line-height: 1.45; padding: 0.1em 0.5ex; text-rendering: optimizespeed; word-spacing: -0.15em;">ComputedConstant</code> is not yet available in the mainline JDK repository. Check out the next section for a link to the proposed source code.</span></p></div></div></div><div class="sect1 has-source-line data-line-stdin-178" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px 0px 1.25em;"><h2 id="_resources" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Resources</span></h2><div class="sectionbody" style="box-sizing: border-box; margin: 0px; padding: 0px;"><div class="ulist has-source-line data-line-stdin-180" style="box-sizing: border-box; margin: 0px; padding: 0px;"><ul style="box-sizing: border-box; font-family: inherit; line-height: 1.6; list-style-position: outside; margin: 0px 0px 1.25em 1.5em; padding: 0px;"><li class="has-source-line data-line-stdin-180" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 0.625em; padding: 0px; text-rendering: optimizelegibility;"><a href="https://openjdk.org/jeps/8312611" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: none white; box-sizing: border-box; color: #589df6; line-height: inherit;">JEP draft: Computed Constants</a></p></li><li class="has-source-line data-line-stdin-181" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 0.625em; padding: 0px; text-rendering: optimizelegibility;"><a href="https://cr.openjdk.org/~pminborg/computed-constant/api/java.base/java/lang/ComputedConstant.html" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: none white; box-sizing: border-box; color: #589df6; line-height: inherit;">Proposed ComputedConstant API</a></p></li><li class="has-source-line data-line-stdin-182" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 0.625em; padding: 0px; text-rendering: optimizelegibility;"><a href="https://github.com/openjdk/leyden/blob/computed-constants/src/java.base/share/classes/java/lang/ComputedConstant.java" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: none white; box-sizing: border-box; color: #589df6; line-height: inherit;">Proposed Source Code</a></p></li><li class="has-source-line data-line-stdin-183" style="box-sizing: border-box; margin: 0px; padding: 0px;"><p style="box-sizing: border-box; font-size: 1.0625rem; letter-spacing: -0.01em; line-height: 1.6; margin: 0px 0px 0.625em; padding: 0px; text-rendering: optimizelegibility;"><a href="https://github.com/openjdk/leyden/blob/computed-constants/test/micro/org/openjdk/bench/java/lang/ComputedConstantStatic.java" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: none white; box-sizing: border-box; color: #589df6; line-height: inherit;">Benchmarks</a></p></li></ul></div></div></div><div class="sect1 has-source-line data-line-stdin-185" style="border-top: 1px solid rgb(231, 231, 233); box-sizing: border-box; color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 16px; margin: 0px; padding: 0px;"><h2 id="_acknowledgements" style="box-sizing: border-box; color: #cccccc; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-size: 2.3125em; font-weight: 300; letter-spacing: -0.01em; line-height: 1.2; margin: 1em 0px 0.5em; padding: 0px; text-rendering: optimizelegibility; word-spacing: -0.05em;"><span style="background-color: white;">Acknowledgments</span></h2></div><p><span style="background-color: white;"><span style="color: #bbbbbb; font-family: "Noto Serif", "DejaVu Serif", serif; font-size: 1.0625rem; letter-spacing: -0.01em;">Parts of the text in this article were written by Maurizio Cimadamore</span> </span></p>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-54195557212723003702023-02-16T00:01:00.001-08:002023-02-16T00:01:40.528-08:00Video: Project Panama and the Foreign Function and Memory API<p><br /></p><p>The “Foreign Function and Memory API” (FFM), previewed in Java 20, allows Java programs to interoperate safely with code and data outside the Java runtime. In this fast-paced talk, we will explore what the FFM API has to offer and, via a hands-on live coding example, see how the promises of FFM can be realized in your code today. The live-code example involves integrating and using a native system call directly from Java.</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://www.youtube.com/watch?v=8sFt1_7RxGk" style="margin-left: 1em; margin-right: 1em;" target="_blank"><img alt="" data-original-height="263" data-original-width="359" height="234" src="https://blogger.googleusercontent.com/img/a/AVvXsEgzjLdfD6GJeR7-lp9F72S3UQrIEGtYoODWBfe1vki-xP1sIYCHTm0Yvh5NrDiUsTWlAWC58zuHTfABFApcTIDaTwC1GOokf7-1UjqVpfm2-6qM3Hsj9C3JyfhGASJBCBE_1i6R15l9MYsGE62bTHmVmT4f7Ysa5qt9twi8L-1EuJnHfG3LMuqcDOit" width="320" /></a></div><br /><br /><p></p><p>Here is a <a href="https://www.youtube.com/watch?v=8sFt1_7RxGk">link to the 15-minute presentation</a>.</p><p>The presentation was made at jFocus 2023 in Stockholm</p>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Stockholm, Sweden59.329323499999987 18.068580831.019089663821141 -17.0876692 87.639557336178825 53.2248308tag:blogger.com,1999:blog-4815481734454081491.post-60806430089082379532023-02-13T01:40:00.002-08:002023-02-13T01:40:47.450-08:00JDK 21: Image Performance Improvements<p><br /></p><div dir="auto" style="box-sizing: border-box;"><h2 dir="auto" id="user-content-introduction" style="border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;">Introduction</h2><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">In a<span class="Apple-converted-space"> </span><a href="https://github.com/minborg/articles/blob/image-perf/2023/January/26-PerformanceImprovementsRevealed" style="box-sizing: border-box; text-decoration-line: none;">previous article</a>, I talked about how serialization and file I/O performance was improved in JDK 21 thanks to the use of<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">VarHandle</code>constructs. The method employed there has now also been applied to Java’s image-handling library making it faster. Here is what happened:</p></div></div></div><div dir="auto" style="box-sizing: border-box;"><h2 dir="auto" id="user-content-background" style="border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;"><a aria-hidden="true" class="anchor" href="https://github.com/minborg/articles/blob/image-perf/2023/February/13-ImagePerformanceImprovements/README.adoc#background" id="user-content-background" style="box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z" fill-rule="evenodd"></path></svg></a>Background</h2><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">When packing/unpacking primitive values (such as<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">int</code><span class="Apple-converted-space"> </span>and<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">long</code><span class="Apple-converted-space"> </span>primitives) into/from a byte array, conversion was previously made using explicit bit shifting as shown in the<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">ImageInputStreamImpl::readInt</code><span class="Apple-converted-space"> </span>method below:</p></div><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" style="box-sizing: border-box; margin-bottom: 16px; overflow: auto !important; position: relative !important;"><pre style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">public</span> <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">int</span> <span class="pl-s1" style="box-sizing: border-box;">readInt</span>() <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">throws</span> <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">IOException</span> {
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">if</span> (<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">read</span>(<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>, <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>, <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">4</span>) != <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">4</span>) {
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">throw</span> <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">new</span> <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">EOFException</span>();
}
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">if</span> (<span class="pl-s1" style="box-sizing: border-box;">byteOrder</span> == <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">ByteOrder</span>.<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">BIG_ENDIAN</span>) {
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">return</span>
(((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">24</span>) | ((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">1</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">16</span>) | <span class="pl-c" style="box-sizing: border-box; color: var(--color-prettylights-syntax-comment);">// (1)</span>
((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">2</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">8</span>) | ((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">3</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>));
} <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">else</span> {
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">return</span>
(((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">3</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">24</span>) | ((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">2</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">16</span>) | <span class="pl-c" style="box-sizing: border-box; color: var(--color-prettylights-syntax-comment);">// (2)</span>
((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">1</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">8</span>) | ((<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>[<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>] & <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0xff</span>) << <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>));
}
}</pre></div></div><div dir="auto" style="box-sizing: border-box;"><ol dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;"><li style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;"><em style="box-sizing: border-box;">Big-endian</em><span class="Apple-converted-space"> </span>unpacking via bit shifting</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;"><em style="box-sizing: border-box;">Little-endian</em><span class="Apple-converted-space"> </span>unpacking via bit shifting</p></li></ol></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">The scheme used here is similar to what is described in my<span class="Apple-converted-space"> </span><a href="https://github.com/minborg/articles/blob/image-perf/2023/January/26-PerformanceImprovementsRevealed" style="box-sizing: border-box; text-decoration-line: none;">previous article</a><span class="Apple-converted-space"> </span>so, I will not dive into the details again. In short, this method is complex and challenging for Java to fully optimize. Also, it is hard to read for us humans.</p></div></div></div><div dir="auto" style="box-sizing: border-box;"><h2 dir="auto" id="user-content-improvements-in-jdk-21" style="border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;"><a aria-hidden="true" class="anchor" href="https://github.com/minborg/articles/blob/image-perf/2023/February/13-ImagePerformanceImprovements/README.adoc#improvements-in-jdk-21" id="user-content-improvements-in-jdk-21" style="box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z" fill-rule="evenodd"></path></svg></a>Improvements in JDK 21</h2><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">In Java 21, conversions are instead made with<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">VarHandle</code><span class="Apple-converted-space"> </span>constructs via the new<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">jdk.internal.util.ByteArray class</code>. Here is what parts of the internal<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">ByteArray</code><span class="Apple-converted-space"> </span>class look like:</p></div><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" style="box-sizing: border-box; margin-bottom: 16px; overflow: auto !important; position: relative !important;"><pre style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">private</span> <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">static</span> <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">final</span> <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">VarHandle</span> <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">INT</span> =
<span class="pl-s1" style="box-sizing: border-box;">MethodHandles</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">byteArrayViewVarHandle</span>(<span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">int</span>[], <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">ByteOrder</span>.<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">BIG_ENDIAN</span>);
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">static</span> <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">int</span> <span class="pl-s1" style="box-sizing: border-box;">getInt</span>(<span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">byte</span>[] <span class="pl-s1" style="box-sizing: border-box;">b</span>, <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">int</span> <span class="pl-s1" style="box-sizing: border-box;">off</span>) {
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">return</span> (<span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">int</span>) <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">INT</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">get</span>(<span class="pl-s1" style="box-sizing: border-box;">b</span>, <span class="pl-s1" style="box-sizing: border-box;">off</span>);
}</pre></div></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">Using VarHandles means Java is able to optimize methods better compared to explicit bit shifting. Again, you can read more about<span class="Apple-converted-space"> </span><a href="https://github.com/minborg/articles/blob/image-perf/2023/January/26-PerformanceImprovementsRevealed" style="box-sizing: border-box; text-decoration-line: none;">how VarHandles work in my previous article</a>.</p></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">The class above handles<span class="Apple-converted-space"> </span><em style="box-sizing: border-box;">big-endian</em>. As images need to be able to handle also<span class="Apple-converted-space"> </span><em style="box-sizing: border-box;">little-endian</em><span class="Apple-converted-space"> </span>a new class called<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">ByteArrayLittleEndian</code>was added. This means the<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">readInt()</code><span class="Apple-converted-space"> </span>method can be simplified and improved like this:</p></div><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" style="box-sizing: border-box; margin-bottom: 16px; overflow: auto !important; position: relative !important;"><pre style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">public</span> <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">int</span> <span class="pl-s1" style="box-sizing: border-box;">readInt</span>() <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">throws</span> <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">IOException</span> {
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">if</span> (<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">read</span>(<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>, <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>, <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">4</span>) != <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">4</span>) {
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">throw</span> <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">new</span> <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">EOFException</span>();
}
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">return</span> (<span class="pl-s1" style="box-sizing: border-box;">byteOrder</span> == <span class="pl-smi" style="box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);">ByteOrder</span>.<span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">BIG_ENDIAN</span>)
? <span class="pl-s1" style="box-sizing: border-box;">ByteArray</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">getInt</span>(<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>, <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>)
: <span class="pl-s1" style="box-sizing: border-box;">ByteArrayLittleEndian</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">getInt</span>(<span class="pl-s1" style="box-sizing: border-box;">byteBuf</span>, <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">0</span>);
}</pre></div></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">Nice! It looks much cleaner now.</p></div></div></div><div dir="auto" style="box-sizing: border-box;"><h2 dir="auto" id="user-content-affected-classes-and-impact" style="border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;"><a aria-hidden="true" class="anchor" href="https://github.com/minborg/articles/blob/image-perf/2023/February/13-ImagePerformanceImprovements/README.adoc#affected-classes-and-impact" id="user-content-affected-classes-and-impact" style="box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z" fill-rule="evenodd"></path></svg></a>Affected Classes and Impact</h2><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">The following classes were directly improved:</p></div><div dir="auto" style="box-sizing: border-box;"><ul dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;"><li style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;"><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">ImageInputStreamImpl</code></p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;"><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">ImageOutputStreamImpl</code></p></li></ul></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">The good news is that these classes provide the foundation for a large number of other image-handling classes in the<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">javax.imageio.stream</code><span class="Apple-converted-space"> </span>package and perhaps elsewhere (after all, the above classes are in the public API).</p></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">This means, in many cases, image handling becomes faster and all third-party libraries relying on any of the classes above (directly or indirectly) will also run faster with no change in your application code.</p></div></div></div><div dir="auto" style="box-sizing: border-box;"><h2 dir="auto" id="user-content-benchmarks" style="border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;"><a aria-hidden="true" class="anchor" href="https://github.com/minborg/articles/blob/image-perf/2023/February/13-ImagePerformanceImprovements/README.adoc#benchmarks" id="user-content-benchmarks" style="box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z" fill-rule="evenodd"></path></svg></a>Benchmarks</h2><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">In the benchmarks below, I have used Java 17 as a baseline meaning that other Java 21 performance improvements will also contribute to higher performance. I have run the benchmarks using my Mac M1 aarch64 but the benchmarks are available<span class="Apple-converted-space"> </span><a href="https://github.com/openjdk/jdk/tree/master/src/demo/share/java2d/J2DBench" style="box-sizing: border-box; text-decoration-line: none;">here</a><span class="Apple-converted-space"> </span>for anyone to run.</p></div><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><a href="https://github.com/minborg/articles/blob/image-perf/2023/February/13-ImagePerformanceImprovements/Graph1.png" rel="noopener noreferrer" style="box-sizing: border-box; text-decoration-line: none;" target="_blank"><img alt="Graph 1" src="https://github.com/minborg/articles/raw/image-perf/2023/February/13-ImagePerformanceImprovements/Graph1.png" style="border-style: none; box-sizing: content-box; max-width: 100%;" /></a></div></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;"><em style="box-sizing: border-box;">Graph 1 shows the performance of the<span class="Apple-converted-space"> </span><code style="border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; white-space: break-spaces;">ImageInputStreamImpl::readInt</code><span class="Apple-converted-space"> </span>method for Java 17 and Java 21.</em></p></div><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">So, the throughput of the benchmarked method has improved from about 579,800,000 bytes/s to around 639,000,000 bytes/s on my machine which is more than a 10% improvement! Not too bad!</p></div></div></div><div dir="auto" style="box-sizing: border-box; margin-bottom: 0px !important;"><h2 dir="auto" id="user-content-actual-application-performance-increase" style="border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;"><a aria-hidden="true" class="anchor" href="https://github.com/minborg/articles/blob/image-perf/2023/February/13-ImagePerformanceImprovements/README.adoc#actual-application-performance-increase" id="user-content-actual-application-performance-increase" style="box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z" fill-rule="evenodd"></path></svg></a>Actual Application Performance Increase</h2><div dir="auto" style="box-sizing: border-box;"><div dir="auto" style="box-sizing: border-box;"><p dir="auto" style="box-sizing: border-box; margin-bottom: 16px; margin-top: 0px;">How much faster will your image applications run under Java 21 in reality? There is only one way to find out: Run your own code on JDK 21 today by downloading a<span class="Apple-converted-space"> </span><a href="https://jdk.java.net/" rel="nofollow" style="box-sizing: border-box; text-decoration-line: none;">JDK 21 Early-Access Build</a>.</p></div></div></div></div></div></div>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-62446411534969093702023-01-26T05:54:00.003-08:002023-02-16T00:04:24.325-08:00Java 21: Performance Improvements Revealed<p> In Java 21, old code might run significantly faster due to <a href="https://github.com/openjdk/jdk/pull/12076" target="_blank">recent internal performance optimizations</a> made in the Java Core Libraries. In this article, we will take a closer look at some of these changes and see how much faster your favorite programming language has become. Buckle up, for we are about to run at full speed!</p><h3 style="text-align: left;">Background</h3><p>When converting primitive values such as <span style="font-family: courier;">int</span> and <span style="font-family: courier;">long</span> values back and forth to certain external representations, such as a file, the internal class <span style="font-family: courier;">java.io.Bits</span> is used. In previous Java versions, conversion in this class was made using explicit bit shifting as shown hereunder:</p><p><span style="font-family: courier;">static long getLong(byte[] b, int off) {</span></p><p><span style="font-family: courier;"> return ((b[off + 7] & 0xFFL) ) +</span></p><p><span style="font-family: courier;"> ((b[off + 6] & 0xFFL) << 8) +</span></p><p><span style="font-family: courier;"> ((b[off + 5] & 0xFFL) << 16) +</span></p><p><span style="font-family: courier;"> ((b[off + 4] & 0xFFL) << 24) +</span></p><p><span style="font-family: courier;"> ((b[off + 3] & 0xFFL) << 32) +</span></p><p><span style="font-family: courier;"> ((b[off + 2] & 0xFFL) << 40) +</span></p><p><span style="font-family: courier;"> ((b[off + 1] & 0xFFL) << 48) +</span></p><p><span style="font-family: courier;"> (((long) b[off]) << 56);</span></p><p><span style="font-family: courier;">}</span></p><p>When taking a closer look, it can be seen that the code will extract a long from a backing byte array by successively extracting a byte value and left-shifting it various steps and then summing the bytes together. </p><p>As the lowest-index byte is the most significant (i.e. it is shifted to the left the most), extraction is made in <i>big-endian</i> order (also called “network order”). There are eight similar steps in the algorithm, where each step is on a separate line, and each step comprises six sub-operations:</p><p></p><ol style="text-align: left;"><li>Add a constant to the provided off parameter</li><li>Extract a byte value at an index from the provided b array including checking index bounds</li><li>Convert the byte value to a long (as an AND operation with another long on the LHS is imminent)</li><li>Perform an AND operation with the long value 0XFF</li><li>Shift the result to the left a number of steps</li><li>Accumulate the resulting value (via the + operation)</li></ol><p></p><p>Hence, there are eight times six operations in total (= 48 operations) that need to be performed. In reality, Java is able to optimize these operations slightly, for example by leveraging CPU instructions that can perform several operations in a single step.</p><p>Calling <span style="font-family: courier;">getLong()</span> from an outer loop entails checking index bounds many times as it is difficult to hoist boundary checking outside the outer loop due to the method’s complexity.</p><h3 style="text-align: left;">Improvements in Java 21</h3><p>In Java 21, conversions are made with <span style="font-family: courier;">VarHandle</span> constructs instead and the class <span style="font-family: courier;">java.io.Bits</span> was moved and renamed to <span style="font-family: courier;">jdk.internal.util.ByteArray</span> so that other classes from various packages could benefit from it too. Here is what the <span style="font-family: courier;">ByteArray::getLong</span> method looks like in Java 21:</p><p><span style="font-family: courier;">private static final VarHandle LONG = </span></p><p><span style="font-family: courier;"> MethodHandles.byteArrayViewVarHandle(long[], ByteOrder.BIG_ENDIAN);</span></p><p><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;">static long getLong(byte[] b, int off) {</span></p><p><span style="font-family: courier;"> return (long) LONG.get(b, off);</span></p><p><span style="font-family: courier;">}</span></p><p>Here, It looks like only one operation is made. However, in reality, there are several things going on under the covers of the <span style="font-family: courier;">VarHandle::get</span> operation. On platforms using little-endian (which is almost 100% of the user base), the byte order needs to be swapped. Also, index bounds must be checked. </p><p>The cast <span style="font-family: courier;">(long)</span> is needed in order to prevent auto-boxing/un-boxing for the return value of the <span style="font-family: courier;">LONG</span> <span style="font-family: courier;">VarHandle</span>. The inner workings of <span style="font-family: courier;">VarHandle</span> objects and their coordinates are otherwise beyond the scope of this article.</p><p>As <span style="font-family: courier;">VarHandles</span> are first-class citizens of the Java language, significant effort has been put into making them efficient. One can only assume the byte-swapping operations are optimized for the platform at hand. Also, the array bounds checking can be hoisted outside the many sub-steps so only one check is needed.</p><p>In addition to internal boundary-check hoisting, The <span style="font-family: courier;">VarHandle</span> construct makes it easier for Java to further hoist boundary checks outside an outer loop compared to the older, more complex, implementation used in pre-Java 21.</p><p>Almost all methods in <span style="font-family: courier;">Bits</span>/<span style="font-family: courier;">ByteArray</span> got rewritten, not only <span style="font-family: courier;">getLong()</span>. So, both reading and writing <span style="font-family: courier;">short</span>, <span style="font-family: courier;">int</span>, <span style="font-family: courier;">float</span>, <span style="font-family: courier;">long</span>, and, <span style="font-family: courier;">double</span> values are now much faster.</p><h3 style="text-align: left;">Affected Classes and Impact</h3><p>The improved <span style="font-family: courier;">java.util.ByteArray</span> class is used directly by the following Core Library classes:</p><p></p><ul style="text-align: left;"><li>ObjectInputStream</li><li>ObjectOutputStream</li><li>ObjectStreamClass</li><li>RandomAccessFile</li></ul><p></p><p><br /></p><p>Even though it appears the direct usage of <span style="font-family: courier;">ByteArray</span> is limited, there is an enormous transitive use of these classes. For example, the three Object Stream classes above are used extensively in conjunction with serialization. </p><p>This means, in many cases, <u>Java serialization is much faster now</u>!</p><p>The <span style="font-family: courier;">RandomAccessFile</span> class is used internally in the JDK for graphics and sound input/output as well as Zip and directory handling. </p><p>More importantly, there is a large number of third-party libraries that relies on these improved classes. They and all applications that are using them will automatically benefit from these improvements in speed. No change in your application code is needed. It just runs faster!</p><p><br /></p><h3 style="text-align: left;">Raw Benchmarks</h3><p>The details of the first benchmarks shown hereunder are described in <a href="https://github.com/openjdk/panama-foreign/pull/762" target="_blank">this pull request</a>. The actual change of <span style="font-family: courier;">Bits</span> was made via <a href="https://github.com/openjdk/jdk/pull/11840" target="_blank">this pull request</a>.</p><p>I have run the benchmarks under Linux x64, Windows x64, and Mac aarch64. Note that this implied running them on different hardware, so these results can’t be compared across operating systems. In other words, Mac aarch64 is not necessarily faster than Linux x64.</p><p>I’ve run the tests using the above <span style="font-family: courier;">ByteArray::readLong</span> method and I’ve used an outer loop with two iterations writing long values into an array. The more iterations in the outer loop, the more pronounced advantages we get with the VarHandle access. One reason for this is likely the C2 compiler is able to hoist out boundary checks outside the outer loop.</p><p><br /></p><p><span id="docs-internal-guid-c36f7480-7fff-059a-a9ff-16bd2d645abe"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 413px; overflow: hidden; width: 675px;"><img alt="image" height="413" src="https://lh5.googleusercontent.com/B1sTjiFELB27BwMNtwFGMIUk8fFTe02ypVbW6pd_1m5D8N3BB_FsxRjogATsGUjuirKOq5mSffLEAxB2niMrXhELj0u04m6s_8bDYxRwXEHXEUvf8fc6hYCEpOSxv_FFi7nyGZuH10gxX6rUXGsl2Bm3Wj6LTjkA1B-yCQf3bA0TiZ4kaIvHrNSlQGioKg" style="margin-left: 0px; margin-top: 0px;" width="675" /></span></span></span></p><p><i>Graph 1 shows the improvement in speed in Bits for various platforms.</i></p><p><br /></p><h3 style="text-align: left;">Serialization Benchmarks</h3><p>So, given the performance increase in <span style="font-family: courier;">ByteArray</span> looks awesome, what will be the practical effect on serialization given all the other things that need to happen during the serialization process?</p><p>Consider the following classes that contain all the primitive types (except <span style="font-family: courier;">boolean</span>):</p><p><span style="font-family: courier;">static final class MyData implements Serializable {</span></p><p><span style="font-family: courier;"> byte b;</span></p><p><span style="font-family: courier;"> char c;</span></p><p><span style="font-family: courier;"> short s;</span></p><p><span style="font-family: courier;"> int i;</span></p><p><span style="font-family: courier;"> float f;</span></p><p><span style="font-family: courier;"> long l;</span></p><p><span style="font-family: courier;"> double d;</span></p><p><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;"> public MyData(byte b, char c, short s, int i, float f, long l, double d) {</span></p><p><span style="font-family: courier;"> this.b = b;</span></p><p><span style="font-family: courier;"> this.c = c;</span></p><p><span style="font-family: courier;"> this.s = s;</span></p><p><span style="font-family: courier;"> this.i = i;</span></p><p><span style="font-family: courier;"> this.f = f;</span></p><p><span style="font-family: courier;"> this.l = l;</span></p><p><span style="font-family: courier;"> this.d = d;</span></p><p><span style="font-family: courier;"> }</span></p><p><span style="font-family: courier;">}</span></p><p><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;">record MyRecord(byte b,</span></p><p><span style="font-family: courier;"> char c,</span></p><p><span style="font-family: courier;"> shorts,</span></p><p><span style="font-family: courier;"> int i,</span></p><p><span style="font-family: courier;"> float f,</span></p><p><span style="font-family: courier;"> long l,</span></p><p><span style="font-family: courier;"> double d) implements Serializable {}</span></p><p><br /></p><p><br /></p><p>where the complete <span style="font-family: courier;">PrimitiveFieldSerializationBenchmark</span> <a href="https://github.com/openjdk/jdk/tree/master/test/micro/org/openjdk/bench/java/io">is available here</a>. Running these benchmarks that serialize instances of the classes above on my laptop (macOS 12.6.1, MacBook Pro (16-inch, 2021) M1 Max) produced the following result:</p><p><br /></p><p><span style="font-family: courier;">Baseline (20-ea+30-2297)</span></p><p><span style="font-family: courier;">Benchmark Mode Cnt Score Error Units</span></p><p><span style="font-family: courier;">SerializeBenchmark.serializeData avgt 8 7.283 ± 0.070 ns/op</span></p><p><span style="font-family: courier;">SerializeBenchmark.serializeRecord avgt 8 7.275 ± 0.201 ns/op</span></p><p><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;">Java 21</span></p><p><span style="font-family: courier;">SerializeBenchmark.serializeData avgt 8 6.793 ± 0.132 ns/op</span></p><p><span style="font-family: courier;">SerializeBenchmark.serializeRecord avgt 8 6.733 ± 0.032 ns/op</span></p><p><br /></p><p>This is good news! Our classes now serialize more than 5% faster.</p><p><span id="docs-internal-guid-26b785cd-7fff-dbda-1da4-b684efecd287"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 557px; overflow: hidden; width: 892px;"><img height="557" src="https://lh3.googleusercontent.com/MkaeA_BkA22k6R9KvRslCotplwb6WBMc9-xa_fe58kP5O7U36QSct6wKvzn0ymhVUHfbyX6e8hxHy85DLqnMgTRYXDypIqOtfkWN8IB4zpafsZkNZQt3tMtqKebrFliCjlRPDQbzEK7JHb4yF2FS6XtjG8U_ibT4hqxPihCzpggZS0z7D7TXYmNeMvTAyw" style="margin-left: 0px; margin-top: 0px;" width="892" /></span></span></span></p><p><i>Graph 2 shows the improvement in serialization for two classes.</i></p><p><br /></p><h3 style="text-align: left;">Future Improvements</h3><p>There are several other classes in the JDK that look similar and that might benefit from the same type of performance improvements once they are optimized with VarHandle access. </p><p>Caring for old code is a trait of good stewardship!</p><p><br /></p><h3 style="text-align: left;">Actual Application Performance Increase</h3><p>How much faster will your applications run under Java 21 in reality if you use one or more of these improved classes (directly or indirectly)? There is only one way to find out: Run your own code on Java 21 today by downloading a <a href="https://jdk.java.net" target="_blank">JDK 21 Early-Access Build</a>. </p><p><br /></p>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-79492450074999168402023-01-18T03:26:00.010-08:002023-01-18T03:57:23.032-08:00Java 20: An Almost Infinite Memory Segment Allocator<div style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Wouldn’t it be cool if you could allocate an infinite amount of memory? In <a href="http://minborgsjavapot.blogspot.com/2023/01/java-20-colossal-sparse-memory-segments.html" target="_blank">a previous article</a>, I elaborated a bit on how to create memory-mapped files which could be sparse. In this article, we will learn how this can be leveraged as an under-carriage for providing a memory-allocating arena that can return an almost infinite amount of native memory without ever throwing an <span style="font-family: courier;">OutOfMemoryError</span>. </p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><h2 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;">Arena</h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">An <span style="font-family: courier;">Arena</span> controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">There are two built-in <span style="font-family: courier;">Arena</span> types in Java 20:</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"></p><ul style="text-align: left;"><li>A <i>Confined Arena</i> (available via the <span style="font-family: courier;">Arena::openConfined</span> factory)</li><li>A <i>Shared Arena</i> (available via the <span style="font-family: courier;">Arena::openShared</span> factory)</li></ul><p></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">As the names imply, memory segments obtained from a <i>Confined Arena </i>can only be used by the thread that initially created the <span style="font-family: courier;">Arena</span>, whereas memory segments from a <i>Shared Arena</i> can be used by any thread. Both types will allocate pure unmapped native memory.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><h2 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;">The InfiniteArena Class</h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">By creating a new class as shown hereunder, we can provide an implementation that differs from the built-in <span style="font-family: courier;">Arena</span> types in the way that it will provide memory-mapped memory instead of pure native memory.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">The class is using sparse files to reduce required file space on platforms where this is supported.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">import static java.nio.channels.FileChannel.MapMode.READ_WRITE;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">import static java.nio.file.StandardOpenOption.*;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">import static java.util.Objects.requireNonNull;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">public final class InfiniteArena implements Arena {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> private static final Set<OpenOption> OPTS =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> Set.of(CREATE_NEW, SPARSE, READ, WRITE);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> private final String fileName;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> private final AtomicLong cnt;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> private final Arena delegate;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> public InfiniteArena(String fileName) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> this.fileName = requireNonNull(fileName);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> this.cnt = new AtomicLong();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> this.delegate = Arena.openShared();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> public MemorySegment allocate(long byteSize, long byteAlignment) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> try {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> try (var fc = FileChannel.open(</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> Path.of(fileName + "-" + cnt.getAndIncrement()), OPTS)) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> return fc.map(READ_WRITE, 0, byteSize, delegate.scope());</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> } catch (IOException e) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> throw new RuntimeException(e);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> public SegmentScope scope() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> return delegate.scope();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> public void close() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> delegate.close();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> public boolean isCloseableBy(Thread thread) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> return delegate.isCloseableBy(thread);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">As seen above, the parameter <span style="font-family: courier;">byteAlignment</span> in <span style="font-family: courier;">Arena::allocate</span> is ignored in anticipation that mapped memory is super aligned by default on all supporting platforms and that <span style="font-family: courier;">byteAlignment</span> is relatively low. Obviously, in a production system, this has to be handled in a more strict way.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">On my machine (macOS 12.6.1) and using the examples below, mapped memory addresses are always aligned to at least 2^14 = 16,384-byte boundaries.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><h2 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;">Using the InfiniteArena</h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Here is an example of how the <span style="font-family: courier;">InfiniteArena</span> can be used in an application:</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> try (Arena arena = new InfiniteArena("my-mapped-memory")) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> MemorySegment s0 = arena.allocate(1L << 40);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> // Do nothing with s0</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> MemorySegment s1 = arena.allocate(1L << 40);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> // Fill the region 1024 to 1024+256-1 with the value 2</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> s1.asSlice(1024, 256)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> .fill((byte) 2);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> MemorySegment s2 = arena.allocate(16);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> // Write a String to the segment</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> s2.setUtf8String(0, "Hello World");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">In the <i>try-with-resources</i> block, we create an <span style="font-family: courier;">InfiniteArena</span> with a base file name "my-mapped-memory" to be used for the backing mapped files. The <span style="font-family: courier;">Arena</span> is then used to allocate three native <span style="font-family: courier;">MemroySegment</span> instances, where the first two ones are of size 1 TiB and the last is only 16 bytes. Note that, since we are not touching the first segment <span style="font-family: courier;">s0</span> and is only using a small portion of the second segment <span style="font-family: courier;">s1</span>, the required physical disk space is minimal for these segments.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Lastly, a small segment <span style="font-family: courier;">s2</span> of 16 bytes is created in which we put the all-familiar “Hello World” string.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><h2 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;">Inspecting the Files</h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">After the code completes, we can inspect the lingering files:</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">% ls -lart</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">-rw-r--r-- 1 pminborg staff 1099511627776 Jan 9 17:18 my-mapped-memory-0</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">-rw-r--r-- 1 pminborg staff 1099511627776 Jan 9 17:18 my-mapped-memory-1</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">-rw-r--r-- 1 pminborg staff 16 Jan 9 17:18 my-mapped-memory-2</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">As can be seen, the file names are created as <span style="font-family: courier;">my-mapped-memory-X</span> where <span style="font-family: courier;">X</span> is the sequence number of created <span style="font-family: courier;">MemorySegment</span> instances; 0, 1, … The first two are large (1 TiB as expected). We can inspect the actual disk usage of all the files:</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">% du -h my-mapped-memory-*</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> 0B my-mapped-memory-0</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"> 16K my-mapped-memory-1</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">4.0K my-mapped-memory-2</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Here is how they look in detail:</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">% hexdump -C my-mapped-memory-0 </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">% hexdump -C my-mapped-memory-1</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">*</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">00000400 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 |................|</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">*</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">00000500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Note 1: “*” indicates the lines are the same (except the address) until there is another address indication.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Note 2: The <span style="font-family: courier;">hexdump</span> command takes a long time to complete for 1 TiB files so only the first lines of output are shown above.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Here is how the smaller <span style="font-family: courier;">my-mapped-memory–2</span> file looks like:</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">% hexdump -C my-mapped-memory-2</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 00 00 00 00 00 |Hello World.....|</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: courier;">00000010</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Cool! Being able to inspect used memory post-mortem could prove invaluable insights in many cases.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><h2 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;">Drawbacks and Future Improvements</h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">As a file needs to be created upon every allocation, this will slow down allocation speed compared to normal allocation. Also, if all space is actually being used, a sparse file would require more resources than if it was a non-sparse file. It would be trivial to modify the code above to use non-sparse files.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">In the implementation above, the allocated files will remain after the <span style="font-family: courier;">Arena</span> has been closed and indeed even after the JVM exits. This allows the inspection and tracing of memory segments allocated as exemplified above. It is a small thing to add cleaning up lingering files if that is needed. For example, if the program needs to be re-run again without it complaining about files that already exist. It is also possible to use a unique name each time the application runs to avoid file name collisions.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Mapped files can be much larger than the physical RAM but that comes with the price of potentially swapping in and out virtual memory should the accessed memory not be resident.</p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><h2 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;">What’s Next?</h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Try out the <span style="font-family: courier;">InfiniteArena</span> today by downloading <a href="https://jdk.java.net/" target="_blank">a JDK 20 Early-Access Build</a>. Do not forget to pass the <span style="font-family: courier;">--enable-preview</span> JVM flag or your code will not run. </p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p></div>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0tag:blogger.com,1999:blog-4815481734454081491.post-75272346225253212842023-01-09T04:00:00.002-08:002023-01-09T05:21:41.870-08:00Java 20: Colossal Sparse Memory Segments<p><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; white-space: pre-wrap;">Did you know you can allocate memory segments that are larger than the physical size of your machine’s RAM and indeed larger than the size of your entire file system? Read this article and learn how to make use of mapped memory segments that may or may not be “sparse” and how to allocate 64 terabytes of sparse data on a laptop.</span></p><span id="docs-internal-guid-a8ab3b57-7fff-36a7-1cd0-2d50f14ffe0f"><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Mapped Memory</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Mapped memory is virtual memory that has been assigned a one-to-one mapping to a portion of a file. The term “file” is quite broad here and may be represented by a regular file, a device, shared memory or any other thing that the operating system may refer to via a file descriptor.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Accessing files via mapped memory is often much faster than accessing a file via the standard file operations like </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">read</span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">write</span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Because mapped memory is operated on directly, some interesting solutions can also be constructed via atomic memory operations such as compare-and-set operations, allowing very efficient inter-thread and inter-process communication channels. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Because not all parts of the mapped virtual memory must reside in real memory at the same time, a mapped memory segment might be much larger than the physical RAM in the machine it is running in. If a portion of the mapped memory is not available when accessed, the operating system will temporarily suspend the current thread and load the missing page after which operation may resume again.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Other advantages of mapped files are; they can be shared across processes running different JVMs and, the files remain persistent and can be inspected using any file tool like </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">hexdump</span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Setting up a Mapped Memory Segment</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The new </span><a href="https://openjdk.org/jeps/434" style="text-decoration-line: none;"><span face=""Source Sans Pro", sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Foreign Function and Memory</span></a><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> feature that previews for the second time in Java 20 allows large memory segments to be mapped to a file. Here is how you can create a memory segment of size 4 GiB backed by a file.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Set<OpenOption> opts = Set.of(CREATE, READ, WRITE);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">try (FileChannel fc = FileChannel.open(Path.of("myFile"), opts);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Arena arena = Arena.openConfined()) {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> MemorySegment mapped = </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> fc.map(READ_WRITE, 0, 1L << 32, arena.scope());</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> use(mapped);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">} // Resources allocated by "mapped" is released here via TwR</span></p><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Sparse Files</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">A sparse file is a file where information can be stored in an efficient way if not all portions of the file are actually used. A file with large unused “holes” is an example of such a file whereby only the used sections are actually stored in the underlying physical file. In reality, however, the unused holes also consume some resources albeit much less than their used counterparts.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 304px; overflow: hidden; width: 624px;"><img height="304" src="https://lh3.googleusercontent.com/7-fw4KpfvKpwKQ_qXpVgqYdm-Cb-alk4UG3bC_7_KtPdFPbKiGaZL5epHGxKWQZhLHn9nzAF2B97PiTMxHLV9v6TXde6ZEEiFKGoQlOjedbX4LMXR-8-p-17HGG1HN8suE-ZwD0nfDspz8pwS3HS1HAt5KPuwrLPArxdkdFtt5dpd1UWK4mWR9M2TnSjhg" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Figure 1, Illustrates a logical sparse file where only actual data elements are stored in the physical file.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As long as the sparse file is not filled with too much data, it is possible to allocate a sparse file that is much larger than the available physical disk space. For example, it is possible to allocate an empty 10 TB memory segment backed by a sparse file on a filesystem with very little available capacity. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It should be noted that not all platforms support sparse files.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Setting up a Sparsely Mapped Memory Segment </span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Here is an example of how to create and access the contents of a file via a memory-mapped </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> whereby the contents is sparse. For example, expanding the real underlying data in the file as needed automatically:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Set<OpenOption> sparse = Set.of(CREATE_NEW, SPARSE, READ, WRITE);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">try (var fc = FileChannel.open(Path.of("sparse"), sparse);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> var arena = Arena.openConfined()) {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> memorySegment mapped = </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> fc.map(READ_WRITE, 0, 1L << 32, arena.scope());</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> use(mapped);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">} // Resources allocated by "mapped" is released here via TwR</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Note: The file will appear to consist of 4 GiB of data but in reality the file does not use any (apparent) file-system space at all:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">pminborg@pminborg-mac ntive % ll sparse </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-rw-r--r-- 1 pminborg staff 4294967296 Nov 14 16:12 sparse</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">pminborg@pminborg-mac ntive % du -h sparse </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 0B</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sparse</span></p><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Going Colossal</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The implementation of sparse files varies across the many platforms that are supported by Java and consequently, various sparse-file properties will vary depending on where an application is deployed.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> I am using a Mac M1 under macOS Monteray (12.6.1) with 32 GiB RAM and 1 TiB storage (of which 900 GiB are available). </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">I was able to map a single sparse file of up to 64 TiB using a single mapped memory segment on my machine (using its standard settings):</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 4 GiB -> ok as demonstrated above</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 1 TiB -> ok</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 32 TiB -> ok</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 64 TiB -> ok</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">128 TiB -> failed with OutOfMemoryError</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It is possible to increase the amount of mappable memory but this is out of the scope for this article. In real applications, it is better to have smaller portions of a sparse file mapped into memory rather than mapping the entire sparse file in one chunk. These smaller mappings will then act as “windows” into the larger underlying file.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Anyhow, this looks pretty colossal:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-rw-r--r-- 1 pminborg staff 70368744177664 Nov 22 13:34 sparse</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Creating the empty 64 TiB sparse file took about 200 ms on my machine.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Unrelated Observations on Thread Confinement</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen above, it is possible to access the same underlying physical memory from different threads (and indeed even different processes) with file mapping despite being viewed through several distinct </span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">thread-confined</span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face=""Source Sans Pro", sans-serif" style="font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">What’s Next?</span></h2><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Try out mapped segments today by downloading a</span><a href="https://jdk.java.net" style="text-decoration-line: none;"><span face=""Source Sans Pro", sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"> JDK 20 Early-Access Build</span></a><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Do not forget to pass the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">--enable-preview</span><span face=""Source Sans Pro", sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> JVM flag or your code will not run. </span></span>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-20885299965636405942022-12-05T10:25:00.002-08:002022-12-05T10:25:37.943-08:00Java 20: A Sneak Peek on the Panama FFM API (Second Preview)<p><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The new </span><a href="https://openjdk.org/jeps/434" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">JEP 434</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> has just seen daylight and describes the second preview of the ”Foreign Function & Memory API” (or FFM for short) which is going to be incorporated in the upcoming Java 20 release! In this article, we will take a closer look at some of the improvements made from the first preview that debuted in Java 19 via the older </span><a href="https://openjdk.org/jeps/424" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">JEP 424</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><span id="docs-internal-guid-fa59cc99-7fff-de7e-4251-05f15b37da37"><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Getting familiar with the FFM</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This article assumes you are familiar with the FFM API. If not, you can get a good overview via the </span><a href="https://openjdk.org/jeps/434" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">new JEP</span></a></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Short Summary</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Here is a short summary of the FFM changes made in Java 20 compared to Java 19:</span></p><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryAddress</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> abstractions are unified (memory addresses are now modeled by zero-length memory segments);</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySession</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> has been split into </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SegmentScope</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> to facilitate sharing segments across maintenance boundaries.</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The sealed </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryLayout</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> hierarchy is enhanced to facilitate usage with pattern matching in switch expressions and statements (</span><a href="https://openjdk.org/jeps/433" style="text-decoration-line: none;"><span style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">JEP 433</span></a><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span></p></li></ul><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">A </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> models a contiguous region of memory, residing either inside or outside the Java heap. A </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> can also be used in conjunction with memory mapping whereby file contents can be directly accessed via a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Some changes were done between Java 19 and Java 20 with respect to the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> concept. In Java 19, there was a notion named </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryAddress</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> used for “pointers to memory” and function addresses. In Java 20, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment::address</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> returns a raw memory address in the form of a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> rather than a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryAddress</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> object. Additionally, function addresses are now modeled as a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> of length zero. This means the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryAddress</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class was dropped entirely.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SegmentScope</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">All </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances need a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SegmentScope</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> which models the lifecycle of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances. A scope can be associated with several segments, meaning these segments share the same lifecycle and consequently, their backing resources will be released materially at the same time.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In Java 19, the term </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySession</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> was used for lifecycles but was also a closeable segment allocator. In Java 20, a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SegmentScope</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is a much more concise, lifecycle-only concept.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Perpetual Global Scope Allocation</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Native </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances that should live during the entire JVM lifetime can be allocated through the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SegmentScope.global()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> scope (i.e. segment memory associated with this scope will never be released unless the JVM exits). The </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SegmentScope.global()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> scope is guaranteed to be a singleton.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Automatic JVM-Managed Deallocation</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Native </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances that are </span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">managed by the JVM</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> can now be allocated through the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SegmentScope.auto()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> factory:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances associated with new scopes created via the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">auto()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method are also available to all threads but will be automatically managed by the Java garbage collector. This means segments will be released some unspecified time after the segment becomes unreachable. Thus, segments will be released when they are no longer referenced, just like </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> objects allocated via the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer.allocateDirect()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This allows a convenient create-and-forget scheme but also implies giving up exact control of when potentially large segments of off-heap memory are actually released.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Deterministic User-Managed Deallocation via Arena</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Native </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances can also be </span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">managed directly and deterministically</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> via the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> factory methods:</span></p><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena.openConfined()</span></p></li></ul><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena.openShared()</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances associated with an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">openConfined()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will only be available to the thread that first invokes the factory method and the backing memory will exist merely until the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena::close</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method is invoked (either explicitly or by participating in a try-with-resources clause) whereafter accessing any segments associated with the closed </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will throw an exception. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances associated with an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">openShared()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> behave in a similar way except they are available to any thread. Another difference is when arenas of this type are closed, the JVM has to make sure no other threads are in a critical section (to ensure memory addressing integrity while maintaining performance) and so, closing a shared </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is slower than closing a confined </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It should be mentioned that forgetting to invoke the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena::close</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method means; any and all memory associated with the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will remain allocated until the JVM exits. There are no safety nets here and so, a try-with-resource fits nicely for short-lived arenas as it guarantees all the resources of an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> are released, no matter what.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">An </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> can also be used to co-allocate segments in the same scope. This is convenient when using certain data structures with pointers. For example, a linked list that can be dynamically grown by creating new segments when the old ones become full. The referencing pointers are guaranteed to remain valid as all the participating segments are associated with the same scope. Only when the common scope is closed, all the underlying segment resources can be released.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In Java 19, the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySession</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> was similar to the Java 20 </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> but crucially, an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">is</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> not a lifecycle but is now instead </span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">associated</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> with a lifecycle (accessible via the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arena::scope</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method). </span></p><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryLayout and Pattern Matching</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In FFM, a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryLayout</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> can be used to describe the contents of a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. If we, for example, have the following C struct declaration:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">typedef struct Point {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> int x,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> int y</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">} Points[5];</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Then, we can model it in FFM like this:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SequenceLayout pints = MemoryLayout.sequenceLayout(5,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> MemoryLayout.structLayout(</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> ValueLayout.JAVA_INT.withName("x"),</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> ValueLayout.JAVA_INT.withName("y")</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> )</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">).withName("Points");</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Pattern matching (as recently described in </span><a href="https://openjdk.org/jeps/427" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">JEP 427</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">) will arguably be one of the largest improvements to the Java language ever made and of a similar dignity as generics (appearing in Java 5) and lambdas/functions (appearing in Java 8). In Java 20, the sealed hierarchy of the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> was overhauled to provide a pattern-matching-friendly definition. This allows, for example, uncomplicated and concise rendering of memory segments as shown hereunder:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">default String render(MemorySegment segment,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> long offset,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> ValueLayout layout) {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> return layout.name().orElse(layout.toString())+ " = " +</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> switch (layout) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfBoolean b -> Boolean.toString(segment.get(b, offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfByte b -> Byte.toString(segment.get(b, offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfChar c -> Character.toString(segment.get(c, offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfShort s -> Short.toString(segment.get(s, offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfInt i -> Integer.toString(segment.get(i, offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfLong l -> Long.toString(segment.get(l , offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfFloat f -> Float.toString(segment.get(f, offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfDouble d -> Double.toString(segment.get(d, offset));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> case OfAddress a -> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> "0x"+Long.toHexString(segment.get(a, offset).address());</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> };</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The code above can relatively easily be expanded with cases for the complete </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryLayout</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> sealed hierarchy including recursive calls for the types </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SequenceLayout</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">GroupLayout</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and for the more simple </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">PaddingLayout</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As a side note, the javadocs in Java 20 will likely come with a pattern-matching nudger in the form of a graphic rendering of the sealed hierarchy for selected classes (i.e. those tagged with “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">@sealedGraph</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">”). Here is how the graph for </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemoryLayout</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> might look like once Java 20 hits GA:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 481px; overflow: hidden; width: 1369px;"><img height="481" src="https://lh4.googleusercontent.com/-3M4OpV6qYhiDGrjzvdEEP3pyN-jaA0C7fierfKazeA3EcfRCSUaITSs5aFDpEluiMjg1DUzoR6IRLc8C4TV38O61izgZK4VBZ9bWCUNm4mXtaOL2SgkwgWRqtNePcZvZi1yZNrNAOYLIiFVPlHM5ORx_g2A-Rg8Y6xmBJbUU0KTvRWf7TnjpB8SK9-R1A" style="margin-left: 0px; margin-top: 0px;" width="1369" /></span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, the graph and the pattern-matching switch example above correspond and the cases are exhaustive with respect to the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ValueLayout</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> type.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Other Improvements</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Java 20 will also see many other improvements in the FFM API, some of which are summarized hereunder:</span></p><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reduced API surface, making it easier to learn and understand the new API</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Improved documentation</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Ability to access thread local variables in native calls, including </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">errorno</span></p></li></ul><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Show Me the Code!</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Here are some examples of creating </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instances for various purposes:</span></p><br /><h4 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Allocate a 1K </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> for the Entire Duration of an Application’s Lifetime</span></h4><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public static final MemorySegment SHARED_DATA = </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> MemorySegment.allocateNative(1024, MemoryScope.global());</span></p><br /><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Allocate a Small, 32-byte Temporary </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> not Bothering When the Underlying Native Memory is Released</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">var seg = MemorySegment.allocateNative(32, MemoryScope.auto());</span></p><br /><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Co-allocate a New </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> with an Existing Segment</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">var coSegment = MemorySegment.allocateNative(32, seg.scope());</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// Store a pointer to the original segment</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">coSegment.set(ValueLayout.ADDRESS, 0, seg);</span></p><br /><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Allocate a Large, 4 GiB Temporary </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Used by the Current Thread Only</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">try (var arena = Arena.openConfined()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> var confined = arena.allocate(1L << 32);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> use(confined);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">} // Memory in "confined" is released here via TwR</span></p><br /><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Allocate a large, 4 GiB temporary </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> to be Used by Several Threads</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">try (var arena = Arena.openShared()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> var shared = arena.allocate(1L << 32);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> useInParallel(shared);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">} // Memory in "shared" is released here via TwR</span></p><br /><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Access an Array via a </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">int[] intArray = new int[10];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">var intSeg = MemorySegment.ofArray(intArray);</span></p><br /><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Access a </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Buffer</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> (of long in This Example) via a </span><span style="font-family: "Courier New"; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">MemorySegment</span></h3><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">LongBuffer longBuffer = LongBuffer.allocate(20);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">var longSeg = MemorySegment.ofBuffer(longBuffer);</span></p><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">What’s Next?</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Take FFM for a spin today by downloading a</span><a href="https://jdk.java.net" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"> Java 20 Early-Access build</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Do not forget to pass the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">--enable-preview</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> JVM flag or the code will not run. </span></p><br /><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Test how you can benefit from FFM already now and engage with the open-source community via the </span><a href="https://mail.openjdk.org/mailman/listinfo/panama-dev" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">panama mailing list</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></span>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-80190287813769636082022-06-07T05:37:00.000-07:002022-06-07T05:37:34.855-07:00Exhaustive JUnit5 Testing with Combinations, Permutations and Products<p> </p><span id="docs-internal-guid-3161df02-7fff-f72c-5589-1c5afda149be" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 26pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Exhaustive JUnit5 Testing with Combinations, Permutations, and Products</span></h1><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Unit testing constitutes an integral part of the process of providing high-quality software. But, how can one write tests covering all variants of several operations? Read this article and learn how to use JUnit5 in conjunction with combinations, permutations, and products.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Test Support Libraries</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">There are many libraries that make testing better in different aspects. Here are some of them:</span></p><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Agitar One</span></h3><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Agitator automatically creates dynamic test cases, synthesizes sets of input data, and analyzes the results.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="background-color: white; color: #3c4043; font-family: Roboto, sans-serif; font-size: 10.5pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><a href="http://www.agitar.com/solutions/products/software_agitation.html" style="text-decoration-line: none;"><span style="color: #1a73e8; font-family: Roboto, sans-serif; font-size: 10.5pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">http://www.agitar.com/solutions/products/software_agitation.html</span></a></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Chaos Monkey</span></h3><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: #fcfcfc; color: #404040; font-family: Arial; font-size: 12pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Chaos Monkey is responsible for randomly terminating instances in production to ensure that engineers implement their services to be resilient to instance failures.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://netflix.github.io/chaosmonkey/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://netflix.github.io/chaosmonkey/</span></a></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Chronicle Test Framework</span></h3><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This library provides support classes for writing JUnit tests. It supports both JUnit4 and JUnit5. Tools like permutations, combinations, and products can be leveraged to create exhaustive tests. Agitar One can automatically identify and generate tests whereas Chronicle Test Framework provides programmatic support for writing your own tests.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Test-Framework" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://github.com/OpenHFT/Chronicle-Test-Framework</span></a></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this article we will be talking about Chronicle Test Framework.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Objective</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Suppose we have written a custom implementation of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">java.util.List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> called </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MyList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and that we want to test the implementation against a reference implementation such as </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ArrayList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. Further, assume that we have a number of operations O</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: 0.6em; vertical-align: sub;">1</span></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, O</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: 0.6em; vertical-align: sub;">2</span></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, …, O</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: 0.6em; vertical-align: sub;">n</span></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. that we can apply to these objects. The question now is: how can we write tests assuring that the two objects provide the same result regardless of how the operations are applied?</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Combinations, Permutations, and Products</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Before we continue, we remind ourselves of what combinations, permutations, and products are from a mathematical perspective. Assume we have a set </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">X = {A, B, C}</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> then;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The combinations of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">X</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> are:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, B, C]</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The permutations of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">X</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> are:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, B, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, C, B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, A, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, C, A]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C, A, B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C, B, A]</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The permutations of all combinations of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">X</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> are:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, A]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C, A]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C, B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, B, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, C, B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, A, C]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, C, A]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C, A, B]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[C, B, A]</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Where </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[]</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> denotes a sequence of no elements. As can be seen from the sequences above, the number of variants will increase very rapidly as the number of set members increases. This puts a practical limit on the exhaustiveness of the test one can write.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Another concept (not exemplified in this article) is “Products” (aka </span><a href="https://en.wikipedia.org/wiki/Cartesian_product" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Cartesian Products</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">). Suppose we have a sequence </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">s1 = [A, B]</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> of one type and another sequence </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">s2 = [1, 2]</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> of another type then;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The product of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">s1</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">s2</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, 1]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[A, 2]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, 1]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[B, 2]</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Products have many similarities with database “join” operations and relate to nested loops.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Test Framework</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this test, we will be using open-source </span><a href="https://github.com/OpenHFT/Chronicle-Test-Framework" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Chronicle-Test-Framework</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> that supports the aforementioned combination, permutation, and product features. Here is an example:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// Prints: [], [A], [B], [C], [A, B], [B, C], … (8 sequences)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Combination.of("A", "B", "C")</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .forEach(System.out::println)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This prints all the combinations of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">{A, B, C}</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> the result being the same as in the previous chapter. In the same way, the following example will print out all the permutations of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">{A, B, C}</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// Prints: [A, B, C], [A, C, B], [B, A, C], … (6 sequences)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Permutation.of("A", "B", "C")</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .forEach(System.out::println)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this following example, we combine the capabilities of combinations and permutations:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// Prints: [], [A], [B], [C], [A, B], [B, A], …(16 sequences)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Combination.of("A", "B", "C")</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .flatMap(Permutation::of)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .forEach(System.out::println)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The methods above produce a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stream</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Collection</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> elements allowing easy adaptations to other frameworks such as JUnit5.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">When it comes to products, things work slightly differently. Here is an example:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final List<String> strings = Arrays.asList("A", "B");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final List<Integer> integers = Arrays.asList(1, 2);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product.of(strings, integers)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .forEach(System.out::println);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This will print:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product2Impl{first=A, second=1}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product2Impl{first=A, second=2}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product2Impl{first=B, second=1}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product2Impl{first=B, second=2}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">If a more recent Java version is used, the following scheme would typically be used instead:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">record StringInteger(String string, Integer integer){}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product.of(strings, integers, StringInteger::new)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .forEach(System.out::println);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This will produce:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">StringInteger[string=A, integer=1]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">StringInteger[string=A, integer=2]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">StringInteger[string=B, integer=1]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">StringInteger[string=B, integer=2]</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In my opinion, the above is better than the default </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product2Impl</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> tuple because the record is a “nominal tuple” where the names and types of the state elements are declared in the record header compared to the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Product2Impl</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> which relies on generic types and “first” and “second” as names.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Objective</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Suppose that we want to make sure two </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">java.lang.List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> implementations behave the same way for a number of mutating operations. Here, lists contain </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Integer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> values (ie implements </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List<Integer></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">).</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">We start by identifying the mutating operations to use. One (arbitrary) suggestion is to use the following operations:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">list.clear()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">list.add(1)</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">list.remove((Integer) 1) // Will remove the object 1 and not @index 1</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">list.addAll(Arrays.asList(2, 3, 4, 5))</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">list.removeIf(ODD)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Where</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Predicate<Integer> ODD = v -> v % 2 == 1.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this article, we will initially use </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ArrayList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">LinkedList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for comparison.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As the reader might suspect, the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> types are going to be tested against each other with all the possible sequences of operations. But, how can this be achieved?</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Solution</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">JUnit5 provides a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@TestFactory</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> annotation and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">DynamicTest</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects, allowing a test factory to return a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stream</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">DynamicTest</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instances. This is something that we can leverage, as shown below:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private static final Collection<NamedConsumer<List<Integer>>> OPERATIONS =</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Arrays.asList(</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> NamedConsumer.of(List::clear, "clear()"),</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> NamedConsumer.of(list -> list.add(1), "add(1)"),</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> NamedConsumer.of(list -> list.remove((Integer) 1), "remove(1)"),</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> NamedConsumer.of(list -> list.addAll(Arrays.asList(2, 3, 4, 5)),</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> "addAll(2,3,4,5)"),</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> NamedConsumer.of(list -> list.removeIf(ODD), "removeIf(ODD)")</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@TestFactory</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stream<DynamicTest> validate() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return DynamicTest.stream(Combination.of(OPERATIONS)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .flatMap(Permutation::of),</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Object::toString,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> operations -> {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> List<Integer> first = new ArrayList<>();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> List<Integer> second = new LinkedList<>();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> operations.forEach(op -> {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> op.accept(first);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> op.accept(second);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> });</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> assertEquals(first, second);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> });</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This is the entire solution, and when run under IntelliJ (or other similar tools), the following tests will be performed (only the first 16 of the 326 tests are shown for brevity):</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 756px; overflow: hidden; width: 636px;"><img height="756" src="https://lh5.googleusercontent.com/Dd67NpAbJcrjNy9GWxLPKR1pN_5AVFLQPemU3WGDTSuyJYyeeicEW_amRYCCdkpMe1KxuGcPT9y0MECsUUEKdLvXV8tXYp3V2ed_MrqMOw6LariKkf2s9MD4lGZ0byTlrYSpgGvGQHqKmVKP" style="margin-left: 0px; margin-top: 0px;" width="636" /></span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Image 1, Shows the first 16 test runs of the 326 tests.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The reason </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">NamedConumer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is used over the standard </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">java.util.function.Consumer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is that it allows real names to be shown rather than some cryptic lambda reference like </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ListDemoTest$$Lambda$350/0x0000000800ca9a88@3d8314f0.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> It certainly looks better in the output and provides much better debug capabilities.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Expanding the Concept</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Suppose we have a more significant number of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> implementations we’d like to test, such as:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ArrayList</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">LinkedList</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">CopyOnWriteArrayList</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stack</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Vector</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">To expand the concept, we begin by creating a collection of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List<Integer></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> constructors:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">private static final Collection<Supplier<List<Integer>>> CONSTRUCTORS =</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Arrays.asList(</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> ArrayList::new,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> LinkedList::new,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> CopyOnWriteArrayList::new,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Stack::new,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Vector::new);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The reason for working with constructors rather than instances is that we need to be able to create new </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> implementations for each dynamic test.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Now, we only need to do minor modifications to the previous test:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@TestFactory</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stream<DynamicTest> validateMany() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return DynamicTest.stream(Combination.of(OPERATIONS)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .flatMap(Permutation::of),</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Object::toString,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> operations -> {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Create a fresh list of List implementations</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> List<List<Integer>> lists = CONSTRUCTORS.stream()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .map(Supplier::get)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .collect(Collectors.toList());</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // For each operation, apply the operation on each list</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> operations.forEach(lists::forEach);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Test the lists pairwise</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Combination.of(lists)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Filter out only combinations with two lists</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .filter(set -> set.size() == 2)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Convert the Set to a List for easy access below</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .map(ArrayList::new)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Assert the pair equals</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .forEach(pair -> assertEquals(pair.get(0), pair.get(1)))</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> });</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Strictly, this is a bit of cheating as a single dynamic test contains several subtests for a plurality of List pairs. However, It would be reasonably easy to modify the code above to </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">flatMap()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> in the various assertions under separate dynamic tests. This is left to the reader as an exercise.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">A Final Warning</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Combinations, permutations, and products are potent tools that can increase test coverage, but they can also increase the time it takes to run all tests as the number of sequences explodes even with only a moderate increase in the number of input variants. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">For example, here is a list of the number of permutations of all combinations for some given sets </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">S</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> of size s:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><div align="center" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="225"></col><col width="333"></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #181f4c; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #fcfcfc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">s = size(S)</span></p></td><td style="background-color: #181f4c; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #fcfcfc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">poc(s) (permutations of combinations)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">1 </span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">1</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">2</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">2</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">5</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">3</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">16</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">4</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">65</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">5</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">326</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">6</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">1,957</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">7</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">13,700</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">8</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">109,601</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">986,410</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">10</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">986,4101</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">11</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">108,505,112</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Table 1, </span><span style="color: #0e101a; font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">shows the number of permutations of combinations for some set sizes</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">More generally, it can be shown that: poc(s) = poc(s - 1) * s + 1. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">If in doubt, the number of combinations can be checked using the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.count()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> stream operation which will return the number of sequences returned as shown below:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long poc6 = Combination.of(1, 2, 3, 4, 5, 6)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .flatMap(Permutation::of)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .count();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The stream above will, unsurprisingly, return 1,957 as there are six input elements.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Combinatorics can make a huge impact. However, make sure to keep the number of dynamic tests under control, or else test time might increase significantly.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Libraries like </span><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><a href="https://chronicle.software/open-hft/map/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Chronicle Map</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> make use of the </span><a href="https://github.com/OpenHFT/Chronicle-Test-Framework" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Chronicle-Test-Framework</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> to improve testing. Here is an example from Chronicle Map where five Map operations are exhaustively tested providing 326 dynamic tests in just a few lines of code.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 374px; overflow: hidden; width: 1290px;"><img height="374" src="https://lh6.googleusercontent.com/cVZY63Q9HL4g7gq2h6Wqs3sZW5S-sXXoOgnlmzpRNmIld6uCNR3cwck0Rh0Ni04L0I9rDvqNqztSxVkFoZhWCZQQEcs1gPTowtbULTzFTJVNJRncrVWdqQx2qbdUDo4VwlWkp8OAgK_rtcIj" style="margin-left: 0px; margin-top: 0px;" width="1290" /></span></span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Open-Source </span><a href="https://github.com/OpenHFT/Chronicle-Test-Framework" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Chronicle-Test-Framework</span></a></p><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><a href="https://github.com/OpenHFT/Chronicle-Test-Framework/blob/develop/src/test/java/net/openhft/chronicle/testframework/internal/ListDemoTest.java" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">code in this article</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> (Open-Source)</span></span>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-44510021721072046402022-05-09T03:35:00.003-07:002022-05-12T07:05:35.130-07:00Which JVM Version is Fastest?<h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 26pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Which JVM Version is Fastest?</span></h1><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">How is a high-performance, low-latency Java application affected by the JVM version used? Every nanosecond counts for trading and other applications where messages between two different threads are exchanged in about 250 ns! Read this article and find out which JDK variant comes out at the top!</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 18pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Benchmarks</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This article will use open-source Chronicle Queue to exchange 256-byte messages between two threads whereby all messages are also stored in shared memory (</span><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">/dev/shm</span><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is used to minimize the impact of the disk subsystem). </span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Chronicle Queue is a persisted low-latency Java messaging framework for high-performance and critical applications. Because Chronicle Queue is operating on mapped native memory, it eliminates the need for garbage collections giving developers deterministic high performance.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">In the benchmarks, a single producer thread writes messages to a queue with a nanosecond timestamp. Another consumer thread reads the messages from the queue and records the time deltas in a histogram. The producer maintains a sustained message output rate of 100,000 messages per second with a 256-byte payload in each message. Data is measured over 100 seconds so that most jitter will be reflected in the measurements and ensures a reasonable confidence interval for the higher percentiles.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">The target machine has an AMD Ryzen 9 5950X 16-Core Processor running at 3.4 GHz under Linux 5.11.0-49-generic #55-Ubuntu SMP. The CPU cores 2-8 are isolated, meaning the operating system will not automatically schedule any user processes and will avoid most interrupts on these cores.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 18pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The Java Code</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Below, parts of the inner loop of the producer is shown:</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">// Pin the producer thread to CPU 2</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Affinity.setAffinity(2);</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;">try (ChronicleQueue cq = SingleChronicleQueueBuilder.binary(tmp)
</span><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> .blockSize(blocksize)
</span><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> .rollCycle(ROLL_CYCLE)
</span><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> .build()) {</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> ExcerptAppender appender = cq.acquireAppender();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> final long nano_delay = 1_000_000_000L/MSGS_PER_SECOND;</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> for (int i = -WARMUP; i < COUNT; ++i) {</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> long startTime = System.nanoTime();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> try (DocumentContext dc = appender.writingDocument()) {</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> Bytes bytes = dc.wire().bytes();</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> data.writeLong(0, startTime);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> bytes.write(data,0, MSGSIZE);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> long delay = nano_delay - (System.nanoTime() - startTime);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> spin_wait(delay);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In another thread, the consumer thread is running this code in its inner loop (shortened code):</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;">// Pin the consumer thread to CPU 4</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Affinity.setAffinity(4);</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;">try (ChronicleQueue cq = SingleChronicleQueueBuilder.binary(tmp)
</span><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> .blockSize(blocksize)
</span><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> .rollCycle(ROLL_CYCLE)
</span><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> .build()) {</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> ExcerptTailer tailer = cq.createTailer();</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> int idx = -APPENDERS * WARMUP;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while(idx < APPENDERS * COUNT) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> try (DocumentContext dc = tailer.readingDocument()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if(!dc.isPresent())</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> continue;</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> Bytes bytes = dc.wire().bytes();</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> data.clear();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> bytes.read(data, (int)MSGSIZE);</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> long startTime = data.readLong(0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if(idx >= 0)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> deltas[idx] = System.nanoTime() - startTime;</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;"> ++idx;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">As can be seen, the consumer thread will read each nano timestamp and record the corresponding latency in an array. These timestamps are later put in a histogram which is printed when the benchmark completes. Measurements will start only after the JVM has warmed up properly and the C2 compiler has JIT:ed the hot execution path.</span></b></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 18pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JVM Variants</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue officially supports all the recent LTS versions: Java 8, Java 11, and Java 17, and so these will be used in the benchmarks. We will also use the GraalVM community and enterprise edition. Here is a list of the specific JVM variants used:</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none; table-layout: fixed; width: 468pt;"><colgroup><col></col><col></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #212449; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Legend (JVM Variant)</span></p></td><td style="background-color: #212449; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Detail</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">OpenJDK 8</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">1.8.0_322, vendor: Temurin</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">OpenJDK 11</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">11.0.14.1, vendor: Eclipse Adoptium</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">OpenJDK 17</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">17.0.2, vendor: Eclipse Adoptium</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Graal VM CE 17</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">17.0.2, vendor: GraalVM Community</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Graal VM EE 17</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">17.0.2, vendor: Oracle Corporation</span></p></td></tr></tbody></table></div><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; white-space: pre-wrap;">Table 1, Shows the specific JVM variants used.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 18pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Measurements</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As 100,000 messages per second are produced, and the benchmarks run for 100 seconds, there will be 100,000 * 100 = 10 million messages sampled during each benchmark. The histogram used places each sample in a certain percentile: 50% (median), 90%, 99%, 99.9% etc. Here is a table showing the total number of messages received for some percentiles:</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><div align="center" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none; table-layout: fixed; width: 468pt;"><colgroup><col></col><col></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #212449; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Percentile</span></p></td><td style="background-color: #212449; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"># Messages</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0% (all)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 2pt; vertical-align: bottom;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">10,000,000</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">50% (“Median”, used below)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 2pt; vertical-align: bottom;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">5,000,000</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">99%</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 2pt; vertical-align: bottom;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">100,000</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">99.9%</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 2pt; vertical-align: bottom;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">10,000</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">99.99% (used below)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 2pt; vertical-align: bottom;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">1,000</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">99.999%</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 2pt; vertical-align: bottom;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">100</span></p></td></tr></tbody></table></div><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; white-space: pre-wrap;">Table 2, Shows the number of messages for each percentile.</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Assuming a relatively small variance of the measurement values, the confidence interval is likely reasonable for percentiles up to 99.99%. The percentile 99.999% probably requires gathering data for at least half an hour or so rather than just 100 seconds to produce any figures with a reasonable confidence interval.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 18pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Benchmarks Results</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For each Java variant, the benchmarks are run like this:</span></p><p><span style="font-family: "Courier New"; font-size: 11pt; white-space: pre-wrap;">mvn exec:java@QueuePerformance</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Remember that our producer and consumer threads will be locked down to run on the isolated CPU cores 2 and 4, respectively. </span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Here is what a typical process looks like after it has run for a while:</span></p><p><span style="font-family: "Courier New"; font-size: 10pt; white-space: pre-wrap;">$ top</span></p><p><span style="font-family: "Courier New"; font-size: 10pt; white-space: pre-wrap;"> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 10pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">3216555 per.min+ 20 0 92.3g 1.5g 1.1g S 200.0 2.3 0:50.15 java </span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As can be seen, the producer and consumer thread spin-waits between each message and therefore consumes an entire CPU core each. If CPU consumption is a concern, latency and determinism can be traded against lowered power consumption by parking threads for a short period (e.g. </span><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">LockSupport.parkNanos(1000)</span><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">) when no messages are available.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">The figures below are given in nanoseconds (ns) which is essential to understand. </span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Many other latency measurements are made in microseconds (= 1,000 ns) or even milliseconds (= 1,000,000 ns). One ns corresponds roughly to the access time of </span><a href="https://www.intel.com/content/www/us/en/developer/articles/technical/memory-performance-in-a-nutshell.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">a CPU L1 cache</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Here is the result of the benchmarks where all values are given in ns:</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none; table-layout: fixed; width: 468pt;"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #212449; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JDK Variant</span></p></td><td style="background-color: #212449; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Median</span></p></td><td style="background-color: #212449; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">99.99%</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">OpenJDK 8</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">280</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">3,951</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">OpenJDK 11</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">370</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">4,210</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">OpenJDK 17</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">290</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">4,041</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GraalVM CE 17 (*)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">310</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">3,950</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GraalVM EE 17 (*)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">270</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: right;"><span style="background-color: transparent; color: black; font-family: "Courier New"; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">3,800</span></p></td></tr></tbody></table></div><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; white-space: pre-wrap;">Table 3, Shows the latency figures for the various JDKs used.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">(*) Not officially supported by Chronicle Queue.</span></p><p><b style="-webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; caret-color: rgb(0, 0, 0); color: black; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;"><br /></b></p><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="background-color: transparent; color: #434343; font-family: Poppins, sans-serif; font-size: 13.999999999999998pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Typical Latency (median)</span></h3><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">For the typical (median) values, there is no significant difference between the various JDKs except for OpenJDK 11 which is about 30% slower than the other versions. </span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">The fastest of them all is GraalVM EE 17, but the difference compared to OpenJDK 8/OpenJDK 17 is marginal.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Here is a graph with the typical 256-byte message latency for the various JDK variants used (lower is better):</span></p><p><img height="385" src="https://lh3.googleusercontent.com/WflmucQW5YbwHCPD66HKPXBouv0ijmbwzDLpvGUMjheLVAJIwwGibRj3rzK66Ui-WYeGL92L8vhSUaN3bsz2VWpLj3cXvWKakMH2wTS1WOPSplF2JJtQ1-aKYqRFQuClfzgFHVqOTDjavZtY" style="font-family: Poppins, sans-serif; font-size: 11pt; margin-left: 0px; margin-top: 0px; white-space: pre-wrap;" title="Chart" width="624" /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Graph 1, Shows the median (typical) latency in ns for the various JDK variants.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">The typical (median) latency varied slightly from run to run where the figures varied around 5%.</span></p><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="background-color: transparent; color: #434343; font-family: Poppins, sans-serif; font-size: 13.999999999999998pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Higher Percentiles</span></h3><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Looking at the higher percentiles, there is not much difference between the supported JDK variants either. GraalVM EE is slightly faster again but here the relative difference is even smaller. OpenJDK 11 appears to be marginally worse (- 5%) than the other variants, but the delta is comparable within the estimated margin of error.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Here is another graph showing latencies for the 99.99% percentile for the various JDK variants (lower is better):</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 416px; overflow: hidden; width: 673px;"><img height="416" src="https://lh5.googleusercontent.com/qvoJPd9JU6w2rOQ-QkyK9c423tyHVF9o0ADIQgAB-q15x56k5imBbw8oxgHRTS-rS0phMCiaLo92HtqxdPm9bQztgEpn64dsKvAOTSmuPl5aNtuWV7hKyHSNCam3xWbBY1ZkET2RcouX2YRS" style="margin-left: 0px; margin-top: 0px;" title="Chart" width="673" /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Graph 2, Shows the 99.99% percentile latency [ns] for the various JDK variants.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 18pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Conclusions</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In my opinion, the latency figures of Chronicle Queue are excellent. Accessing 64-bit data from main memory takes about 100 cycles (which corresponds to about 30 ns on current hardware). The code above has some logic that has to be executed. Additionally, Chronicle Queue obtains data from the producer, persists data (writes to a memory-mapped file), applies appropriate memory fencing for inter-thread communication and happens-before guarantees, and then makes data available to the consumer. All this typically happens around 600 ns for 256 bytes compared to the single 64-bit memory access at 30 ns. Very impressive indeed.</span></p><p><span style="font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">OpenJDK 17 and GraalVM EE 17 seem to be the best choices for this application, providing the best latency figures. Consider using GraalVM EE 17 over OpenJDK 17 if outliers need to be suppressed or if you really need the lowest possible overall latency.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 18pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Open-source </span><a href="https://chronicle.software/open-hft/queue/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></a><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Open-source </span><a href="https://adoptium.net/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-position: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">JDK</span></a></p><p><span style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" /></p>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-72432974397334220712022-03-29T00:26:00.001-07:002022-03-29T00:26:19.581-07:00How to Reduce Cloud Cost by 99% for EDA Kafka Applications<p> </p><span id="docs-internal-guid-4adc3d53-7fff-898c-a109-0f61efb41f85" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 26pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">How to Reduce Cloud Cost by 99% for EDA Kafka Applications</span></h1><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0e101a; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">While the cloud offers great convenience and flexibility, the operational cost for applications deployed in the cloud can sometimes be significant. This article shows a way to substantially reduce operating costs in latency-sensitive Event-Driven Architecture (EDA) Java applications by migrating from Kafka to Chronicle Queue open-source, a more resource-efficient and </span><a href="https://dzone.com/articles/kafka-vs-chronicle-for-microservices" style="text-decoration-line: none;"><span style="color: #4a6ee0; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">lower-latency</span></a><span style="color: #0e101a; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> queue implementation.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">What is EDA?</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">An EDA application is a distributed application where events (in the form of messages or DTOs) are produced, detected, consumed, and reacted to. Distributed means it might run on different machines or the same machine but in separate processes or threads. The latter concept is used in this article whereby messages are persisted to queues.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Setting the Scene</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Suppose that we have an EDA application with a chain of five services and where we have a requirement that 99.9% of the messages sent from the first producer to the last consumer should have a latency less than 100 ms at a message rate of 1,000 messages per second.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 55px; overflow: hidden; width: 624px;"><img height="55" src="https://lh6.googleusercontent.com/o7GghW6hAwMwFubhVOKU5YyQJ_5KLxJ5NgKTL6_7M6JZK4WiUT4LM8e3mFa0F1J4jnPoFbXxzH0FTJWJr212JUJeuTnVHAhwdXleGp6cOB7ms8w9HlqcZzktbYPX_CRXFLLRRro" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Figure 1, The five Services and the Benchmark are interconnected by six topics/queues.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In other words, the time it takes from sending a message (ie using topic 0) by the Benchmark thread to when a resulting message is received by the Benchmark thread again (ie via topic 5) is only allowed to be higher than 100 ms for on average one messages out of every 1,000 messages which are sent every second.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The messages used in this article are simple. They contain a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> nanosecond timestamp holding the initial timestamp when a message is first posted via topic 0 and an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> value that is increased by one each time the message is propagated from one service to the next (this value is not actually used but illustrates a rudimentary service logic). When a message arrives back at the Benchmark thread, the current nanotime is compared with the original nanotime in the initial message sent on topic 0 to allow the calculation of the total latency across the entire service chain. The latency samples are then subsequently fed into a histogram for later analysis.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen in Figure 1 above, the number of topics/queues is equal to the number of services plus one. Hence, there are six topics/queues because there are five services.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Question</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The question in this article is: How many instances of these chains can we set up on a given hardware and still meet the latency requirement? Or, to rephrase it, how many of these applications can we run and still pay the same price for the hardware used?</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Default Setup</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this article, I have elected to use Apache Kafka because it is one of the most common queue types used in the market. I have also selected Chronicle Queue due to its ability to provide low latency and resource efficiency. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Both Kafka and Chronicle Queue have several configurable options, including replicating data across several servers. In this article, a single non-replicated queue will be used. For performance reasons, the Kafka broker will be run on the same machine as the services, allowing the use of the local loopback network interface.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">KafkaProducer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instances are configured to be </span><a href="https://docs.confluent.io/cloud/current/client-apps/optimizing/latency.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">optimised for low latency</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> (eg setting “acks=1”), and so are the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">KafkaConsumer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instances.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The Chronicle Queue instances are created using the default setup with no explicit optimisation. Hence, the more advanced performance features in Chronicle Queue like CPU-core pinning and busy spin-waiting are not used.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Kafka</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Apache </span><a href="https://kafka.apache.org/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Kafka</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is an open-source distributed event streaming platform for high-performance data pipelines, streaming analytics, data integration, and mission-critical applications used extensively in various EDA applications, especially when several information sources residing in different locations are to be aggregated and consumed. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this benchmark, each test instance will create six distinct Kafka topics, and they are named topicXXXX0, topicXXXX1, … , topicXXXX5 where XXXXX is a random number.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Open-source </span><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is a persisted low-latency messaging framework for high-performance and critical applications. Interestingly, Chronicle Queue uses off-heap memory and memory-mapping to reduce memory pressure and garbage collection impacts, making the product popular within the fintech area where deterministic low latency messaging is crucial.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this other benchmark, each test instance will create six Chronicle Queue instances, named topicXXXX0, topicXXXX1, … , topicXXXX5 where XXXXX is a random number.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Code</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The inner loops for the two different service thread implementations are shown below. They both poll their input queue until being ordered to shut down and, if there are no messages, they will wait for one-eighth of the expected inter-message time before a new attempt is made.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Here is the code:</span></p><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Kafka</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">while (!shutDown.get()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> ConsumerRecords<Integer, Long> records = </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> inQ.poll(Duration.ofNanos(INTER_MESSAGE_TIME_NS / 8));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (ConsumerRecord<Integer, Long> record : records) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> long beginTimeNs = record.value();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int value = record.key();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> outQ.send(new ProducerRecord<>(topic, value + 1, beginTimeNs));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Using the record </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">key()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> to carry an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> value might be a bit unorthodox but allows us to improve performance and simplify the code.</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">while (!shutDown.get()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> try (final DocumentContext rdc = tailer.readingDocument()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> if (rdc.isPresent()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> ValueIn valueIn = rdc.wire().getValueIn();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> long beginTime = valueIn.readLong();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int value = valueIn.readInt();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> try (final DocumentContext wdc =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> appender.writingDocument()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ValueOut valueOut = wdc.wire().getValueOut();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> valueOut.writeLong(beginTime);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> valueOut.writeInt(value + 1);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> } else {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> LockSupport.parkNanos(INTER_MESSAGE_TIME_NS / 8);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Benchmarks</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The benchmarks had an initial warmup phase during which the JVM’s C2 compiler profiled and compiled code for much better performance. The sampling results from the warmup period were discarded.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">More and more test instances were started manually (each with its own five services) until the latency requirements could not be fulfilled anymore. Whilst running the benchmarks, the CPU utilisation was also observed for all instances using the “top” command and averaged over a few seconds.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The benchmarks did not take </span><a href="http://highscalability.com/blog/2015/10/5/your-load-generator-is-probably-lying-to-you-take-the-red-pi.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">coordinated omission</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> into account and were run on Ubuntu Linux (5.11.0-49-generic) with AMD Ryzen 9 5950X 16-Core Processors at 3.4 GHz with 64 GB RAM where the applications were run on the isolated cores 2-8 (7 CPU cores in total) and queues were persisted to a 1 TB NVMe flash device . OpenJDK 11 (11.0.14.1) was used.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> All latency figures are given in ms, 99% means 99-percentile and 99.9% means 99.9-percentile.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Kafka</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The Kafka broker and the benchmarks were all run using the prefix “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">taskset -c 2-8”</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> followed by the respective command (eg </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">taskset -c 2-8 mvn exec:java@Kafka</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">). The following results were obtained for Kafka:</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="display: inline-block; position: relative; width: 100px;"></span></span></p><br /><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="93"></col><col width="136"></col><col width="71"></col><col width="91"></col><col width="128"></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Instances</span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Median Latency </span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">99%</span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">99.9%</span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">CPU Utilisation</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">1</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">19</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">30</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">670%</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">2</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">16</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">72</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">106 (*)</span><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">700% (saturated)</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Table 1, Shows Kafka instances vs latencies and CPU utilisation.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">(*) Over 100 ms on the 99.9-percentile.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, only one instance of the EDA system could be run simultaneously. Running two instances increased the 99.9-percentile, so it exceeded the limit of 100 ms. The instances and the Kafka broker quickly saturated the available CPU resources.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Here is a snapshot from the output from the “top” command when running two instance and a broker (pid 3132946):</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">3134979 per.min+ 20 0 20.5g 1.6g 20508 S 319.6 2.6 60:27.40 java </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">3142126 per.min+ 20 0 20.5g 1.6g 20300 S 296.3 2.5 19:36.17 java </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">3132946 per.min+ 20 0 11.3g 1.0g 22056 S 73.8 1.6 9:22.42 java</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The benchmarks were run using the command “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">taskset -c 2-8 mvn exec:java@ChronicleQueue</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">” and following results were obtained:</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="display: inline-block; position: relative; width: 100px;"></span></span></p><br /><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="93"></col><col width="136"></col><col width="93"></col><col width="87"></col><col width="131"></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Instances</span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Median Latency </span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">99%</span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">99.9%</span></p></td><td style="background-color: #3155a5; border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: white; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">CPU Utilisation</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">1</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.5</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.8</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">5.2%</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">10</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.5</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">79%</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">25</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.5</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">3.6</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">180%</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">50</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.5</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0.9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">5.0</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">425%</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">100</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">1.0</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">5</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">20</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">700% (saturated)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">150</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">2.0</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">7</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">53</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">700% (saturated)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">200</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">3.1</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">9</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">59</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">700% (saturated)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">250</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">4.8</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">12</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">62</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">700% (saturated)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">375</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">8.7</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">23</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">75</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">700% (saturated)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">500</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">11</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">36</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">96</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 0.8999999999999999; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">700% (saturated)</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Table 2, Shows Chronicle Queue instances vs latencies and CPU utilisation.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The sheer efficiency of Chronicle Queue becomes apparent in these benchmarks when 500 instances can be run at the same time meaning we handle 3,000 simultaneous queues and 3,000,000 messages per second on just 7 cores at less than 100 ms delay at the 99.9-percentile.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Comparison</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Here is a chart showing the number of instances vs the 99.9-percentile for the two different queue types:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 385px; overflow: hidden; width: 624px;"><img height="385" src="https://lh6.googleusercontent.com/VLNApHA8NKevU0UOUhCswuknzs9tfGfj9No_oAqrrnAkz0UqSK2OZXRCYlck3jBDDGBtpaMnDL-5cbVfXuhNymetWrZfvAWZNujovIWwcPmJy6yRXk5Y9rLUojPixp7btzyFrOg" style="margin-left: 0px; margin-top: 0px;" title="Chart" width="624" /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Chart 1, Shows Instances vs latencies in ms for the 99.9-percentile.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, the curve for Kafka goes from 30 ms to 106 ms in just one step so the latency growth for Kafka looks like a wall in this scale.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Conclusion</span><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">About four hundred times more applications can be run on the same hardware if a switch is made from Kafka to Chronicle Queue for specific latency-sensitive EDA applications. </span></h2><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">About four hundred times more applications corresponds to a potential of reducing cloud or hardware costs by about 99.8% as illustrated in Char 2 below (less is better). In fact, the cost can barely be seen at all in the scale used:</span></h2><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 480px; overflow: hidden; width: 310px;"><img height="480" src="https://lh5.googleusercontent.com/GM0BlAPwoVzU8BRR2r8S86sjbuHiJgIYJbgwu_lanMflYy3j9WNi5A_afin0-fs80o-2tI6gJvHgfyCUhKr0teayrMeRnckHS8lrTxF8VhYljIBi9_8bk8XJVAWd-VF94GS358c" style="margin-left: 0px; margin-top: 0px;" title="Chart" width="310" /></span></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Chart 2, Shows normalised cost vs queue type (less is better)</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Open-source </span><a href="https://kafka.apache.org/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Apache Kafka</span></a></p><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Open-source </span><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></span>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-68278826117333715612022-01-19T02:32:00.000-08:002022-01-19T02:32:05.291-08:00Did You Know the Fastest Way of Serializing a Java Field is not Serializing it at All?<p> </p><span id="docs-internal-guid-b65aafc5-7fff-0884-5105-376a7ff79e6d" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 26pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Did You Know the Fastest Way of Serializing a Java Field is not Serializing it at All? </span></h1><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This article elaborates on different ways of serializing Java objects and benchmarks performance for the variants. Read this article and become aware of different ways to improve Java serialization performance.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In a previous article about </span><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">open-source Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, there was some benchmarking and method profiling indicating that the speed of serialization had a significant impact on execution performance. After all, this is only to be expected as Chronicle Queue (and other persisted queue libraries) must convert Java objects located on the heap to binary data which is subsequently stored in files. Even for the most internally efficient libraries, this inevitable serialization procedure will largely dictate performance.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Data Transfer Object</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this article, we will use a </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Data Transfer Object</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> (hereafter DTO) named </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> which contains financial information with a relatively large number of fields. The same principles apply to other DTOs in any other business area.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">abstract class MarketData extends SelfDescribingMarshallable {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> long securityId;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> long time;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // bid and ask quantities</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> double bidQty0, bidQty1, bidQty2, bidQty3;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> double askQty0, askQty1, askQty2, askQty3;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // bid and ask prices</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> double bidPrice0, bidPrice1, bidPrice2, bidPrice3;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> double askPrice0, askPrice1, askPrice2, askPrice3;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Getters and setters not shown for clarity</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Default Serialization</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Java’s </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Serializable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marker interface provides a default way to serialize Java objects to/from binary format, usually via the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ObjectOutputStream</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ObjectInputStream</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> classes. The default way (whereby the magic </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">writeObject()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">readObject()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> are not explicitly declared) entails reflecting over an object's non-transient fields and reading/writing them one by one, which can be a relatively costly operation.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue can work with </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Serializable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects but also provides a similar, but faster and more space-efficient way to serialize data via the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">abstract class</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">SelfDescribingMarshallable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. Akin to </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Serializable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects, this relies on reflection but comes with substantially less overhead in terms of payload, CPU cycles, and garbage.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Default serialization often comprises the steps of:</span></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Identifying the non-transient fields using reflection</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Reading/writing the identified non-transient field values using reflection</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Writing/reading the field values to a target format (eg binary format)</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The identification of non-transient fields can be cached, eliminating this step to improve performance.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Here is an example of a class using default serialization:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public final class DefaultMarketData extends MarketData {}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, the class does not add anything over its base class and so it will use default serialization as transitively provided by </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">SelfDescribingMarshallable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Explicit Serialization</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Classes implementing</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Serializable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> can elect to implement two magic </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">private</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> (sic!) methods whereby these methods will be invoked instead of resorting to default serialization.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This provides full control of the serialization process and allows fields to be read using custom code rather than via reflection which will improve performance. A drawback with this method is that if a field is added to the class, then the corresponding logic must be added in the two magic methods above or else the new field will not participate in serialization. Another problem is that private methods are invoked by external classes. This is a fundamental violation of encapsulation.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">SelfDescribingMarshallable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> classes work in a similar fashion but thankfully it does not rely on magic methods and invoking private methods externally. A </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">SelfDescribingMarshallable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> class provides two fundamentally different concepts of serializing: one via an intermediary </span><a href="https://chronicle.software/open-hft/wire/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Wire</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> open-source (which can be binary, text, YAML, JSON, etc) providing flexibility and one implicitly binary providing high performance. We will take a closer look at the latter one in the sections below.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Here is an example of a class using explicit serialization whereby public methods in implementing interfaces are explicitly declared:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public final class ExplicitMarketData extends MarketData {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void readMarshallable(BytesIn bytes) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securityId = bytes.readLong();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> time = bytes.readLong();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidQty0 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidQty1 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidQty2 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidQty3 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askQty0 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askQty1 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askQty2 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askQty3 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidPrice0 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidPrice1 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidPrice2 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bidPrice3 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askPrice0 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askPrice1 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askPrice2 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> askPrice3 = bytes.readDouble();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void writeMarshallable(BytesOut bytes) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeLong(securityId);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeLong(time);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidQty0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidQty1);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidQty2);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidQty3);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askQty0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askQty1);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askQty2);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askQty3);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidPrice0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidPrice1);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidPrice2);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(bidPrice3);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askPrice0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askPrice1);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askPrice2);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.writeDouble(askPrice3);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">It can be concluded that this scheme relies on reading or writing each field explicitly and directly, eliminating the need to resort to slower reflection. Care must be taken to ensure fields are referenced in a consistent order and class fields must also be added to the methods above. </span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Trivially Copyable Serialization</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The concept of </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Trivially Copyable Java Objects</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is derived from and inspired by C++. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> class above contains only primitive fields. In other words, there are no reference fields like </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">String</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or the like. This means that when the JVM lays out the fields in memory, field values can be put adjacent to one another. The way fields are laid out is not specified in the Java standard which allows for individual JVM implementation optimizations. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Many JVMs will sort primitive class fields in descending field size order and lay them out in succession. This has the advantage that read and write operations can be performed on even primitive type boundaries. Applying this scheme on the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ExplicitMarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for example will result in the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long time</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> field being laid out first and, assuming we have the initial field space 64-bit aligned, allows the field to be accessed on an even 64-bit boundary. Next, the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int securityId</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> might be laid out, allowing it and all the other 32-bit fields to be accessed on an even 32-bit boundary. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Imagine instead if an initial </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">byte</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> field were initially laid out, then subsequent larger fields would have to be accessed on uneven field boundaries. This would add a performance overhead for some operations, and would indeed prevent a small set of operations from being performed at all (eg unaligned CAS operations on the ARM architecture).</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">How is this relevant to high-performance serialization? Well, as it turns out, it is possible to access an object’s field memory region directly via </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Unsafe</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and use </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">memcpy</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> to directly copy the fields in one single sweep to memory or to a memory-mapped file. This effectively bypasses individual field access and replaces, in the example above, the many individual field accesses with a single bulk operation. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The way this can be done in a correct, convenient, reasonably portable and safe way is outside the scope of this article. Luckily, this feature is readily available in Chronicle Queue, </span><a href="https://github.com/OpenHFT/Chronicle-Bytes" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">open-source Chronicle Bytes</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and other similar products out-of-the-box.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Here is an example of a class using trivially copyable serialization:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">import static net.openhft.chronicle.bytes.BytesUtil.*;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public final class TriviallyCopyableMarketData extends MarketData {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> static final int START = </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> triviallyCopyableStart(TriviallyCopyableMarketData.class);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> static final int LENGTH = </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> triviallyCopyableLength(TriviallyCopyableMarketData.class);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void readMarshallable(BytesIn bytes) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.unsafeReadObject(this, START, LENGTH);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void writeMarshallable(BytesOut bytes) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bytes.unsafeWriteObject(this, START, LENGTH);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This pattern lends itself well to scenarios where the DTO is reused. Fundamentally, It relies on invoking </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Unsafe</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> under the covers for improved performance.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Benchmarks</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Using JMH, serialization performance was assessed for the various serialization alternatives above using this class:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@State(Scope.Benchmark)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@BenchmarkMode(Mode.AverageTime)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@OutputTimeUnit(NANOSECONDS)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@Fork(value = 1, warmups = 1)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@Warmup(iterations = 5, time = 200, timeUnit = MILLISECONDS)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">@Measurement(iterations = 5, time = 500, timeUnit = MILLISECONDS)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class BenchmarkRunner {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final MarketData defaultMarketData = new DefaultMarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final MarketData explicitMarketData = new ExplicitMarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final MarketData triviallyCopyableMarketData = new TriviallyCopyableMarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Bytes<Void> toBytes = Bytes.allocateElasticDirect();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Bytes<Void> fromBytesDefault = Bytes.allocateElasticDirect();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Bytes<Void> fromBytesExplicit = Bytes.allocateElasticDirect();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Bytes<Void> fromBytesTriviallyCopyable = Bytes.allocateElasticDirect();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public BenchmarkRunner() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> defaultMarketData.writeMarshallable(fromBytesDefault);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> explicitMarketData.writeMarshallable(fromBytesExplicit);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> triviallyCopyableMarketData.writeMarshallable(fromBytesTriviallyCopyable);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public static void main(String[] args) throws Exception {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> org.openjdk.jmh.Main.main(args);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Benchmark</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void defaultWrite() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> toBytes.writePosition(0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> defaultMarketData.writeMarshallable(toBytes);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Benchmark</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void defaultRead() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> fromBytesDefault.readPosition(0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> defaultMarketData.readMarshallable(fromBytesDefault);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Benchmark</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void explicitWrite() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> toBytes.writePosition(0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> explicitMarketData.writeMarshallable(toBytes);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Benchmark</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void explicitRead() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> fromBytesExplicit.readPosition(0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> explicitMarketData.readMarshallable(fromBytesExplicit);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Benchmark</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void trivialWrite() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> toBytes.writePosition(0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> triviallyCopyableMarketData.writeMarshallable(toBytes);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> @Benchmark</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void trivialRead() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> fromBytesTriviallyCopyable.readPosition(0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> triviallyCopyableMarketData.readMarshallable(fromBytesTriviallyCopyable);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 9pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This produced the following output on a MacBook Pro (16-inch, 2019) with 2.3 GHz 8-Core Intel Core i9 CPU under JDK 1.8.0_312, OpenJDK 64-Bit Server VM, 25.312-b07:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Benchmark Mode Cnt Score Error Units</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BenchmarkRunner.defaultRead avgt 5 88.772 ± 1.766 ns/op</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BenchmarkRunner.defaultWrite avgt 5 90.679 ± 2.923 ns/op</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BenchmarkRunner.explicitRead avgt 5 32.419 ± 2.673 ns/op</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BenchmarkRunner.explicitWrite avgt 5 38.048 ± 0.778 ns/op</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BenchmarkRunner.trivialRead avgt 5 7.437 ± 0.339 ns/op</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 10pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BenchmarkRunner.trivialWrite avgt 5 7.911 ± 0.431 ns/op</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Using the various </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> variants, explicit serialization is more than two times faster than default serialization. Trivially copyable serialization is four times faster than explicit serialization and more than ten times faster than default serialization as illustrated in the graph below (lower is better):</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 387px; overflow: hidden; width: 622px;"><img height="387" src="https://lh6.googleusercontent.com/BoHS06DRF8GmgdXdl0EfN7EpNs1iw56EHXLZXMovurbvrh0hP-_Ic8C4xVYGZkie6L3Yf6SsmtDNHU9bl3VHMVrQJp_4ll7KTMfm2-QsTYK9Lw2ilII_QDd6RSAV8VmF3pPJ7eU" style="margin-left: 0px; margin-top: 0px;" title="Chart" width="622" /></span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">More fields generally favour trivially copyable serialization over explicit serialization. Experience shows break-even is reached at around six fields in many cases. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Interestingly, the concept of trivially copyable can be extended to hold data normally stored in reference fields such as a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">String</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or an array field. This will provide even more relative performance increase for such classes. </span><a href="https://chronicle.software/contact-us/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Contact the Chronicle team</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> if you want to learn more,</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Why Does it Matter?</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Serialization is a fundamental feature of externalizing DTOs to persistent queues, sending them over the wire or putting them in an off-heap </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Map</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and otherwise handling DTOs outside the Java heap. Such data-intensive applications will almost always gain performance and experience reduced latencies when the underlying serialization performance is improved.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue (open-source)</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Bytes" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">GitHub Chronicle Bytes (open-source)</span></a></p></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" />Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-21807129956125497342022-01-12T00:05:00.004-08:002022-01-12T00:05:38.383-08:00How the Java Language Could Better Support Composition and Delegation<p> </p><span id="docs-internal-guid-50e7e809-7fff-8edd-6059-1ceeee38098d"><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0b5394; font-family: "Advent Pro", sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 500; vertical-align: baseline; white-space: pre-wrap;">How the Java Language Could Better Support Composition and Delegation</span></h1><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This article outlines a way of improving the Java language to better support composition and delegation. Engage in the discussion and contribute to evolving the Java Language.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The Java language lacks explicit semantic support for composition and delegation. This makes delegating classes hard to write, error-prone, hard to read and maintain. For example, delegating a JDBC </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ResultSet</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> interface entails writing more than 190 delegating methods that essentially provide no additional information, as illustrated at the end of this article, and only add ceremony.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">More generally, in the case of composition, Σ m(i) delegating methods need to be written where m(i) is the number of methods for delegate i (provided that all delegate method signatures are disjunct across all the delegates). </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The concept of language support for delegation is not new and there are numerous articles on the subject, including [Bettini08] and [Kabanov11]. Many other programming languages like Kotlin (“</span><a href="https://kotlinlang.org/docs/delegation.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Derived</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">”) and Scala (“</span><a href="https://docs.scala-lang.org/scala3/reference/other-new-features/export.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">export</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">”) have language support for delegation. </span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In one of my previous articles </span><a href="http://minborgsjavapot.blogspot.com/2021/12/why-general-inheritance-is-flawed-and.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">”Why General Inheritance is Flawed and How to Finally Fix it”</span></a><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, I described why composition and delegation are so important.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">External Tools</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Many IDEs have support for generating delegated methods. However, this neither impacts the ability to read nor understand a delegating class. Studies show that code is generally more read than written. There are third-party libraries that provide delegation (e.g. Lombok) but these are non-standard and provide a number of other drawbacks.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">More generally, it would be possible to implement a subset of the functionality proposed here in third-party libraries leveraging annotation processors and/or dynamic proxies.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Trends and Industry Standards</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As the drawbacks with inheritance were more deeply understood, the trend is to move towards composition instead. With the advent of the module system and generally stricter encapsulation policies, the need for semantic delegation support in the Java language has increased even more.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> I think this is a feature that is best provided within the language itself and not via various third-party libraries. Delegation is a cornerstone of contemporary coding. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In essence, It should be much easier to “Favor composition over inheritance” as stated in the book “Effective Java” by Joshua Bloch [Bloch18, Item 18].</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Java Record Classes</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Many of the problems identified above were also true for data classes before record classes were introduced in Java 14. Upon more thorough analysis, there might be a substantial opportunity to harvest many of the findings made during the development of records and apply these in the field of delegation and composition.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">On the Proposal</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">My intention with this article is not to present a concrete proposal of a way to introduce semantic support for composition and delegation in Java. On the contrary, if this proposal is one of the often 10-15 different discarded initial proposals and sketches on the path that needs to be traversed before a real feature can be proposed in the Java language, it will be a huge success. The way towards semantic support for composition and delegation in Java is likely paved with a number of research papers, several design proposals, incubation, etc. This feature will also compete against other features, potentially deemed to be more important to the Java ecosystem as a whole.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">One motto for records was “model data as data” and I think that we should also “model delegation as <span style="font-size: 14.6667px;">delegation</span>”. But what is delegation? There are likely different views on this within the community. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">When I think of delegation, the following springs to mind: A delegating class has the following properties:</span></p><br /><ol style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: upper-alpha; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Has one or more delegates</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: upper-alpha; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Delegates methods from its delegates</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: upper-alpha; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Encapsulates its delegates completely</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: upper-alpha; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Implements and/or uses methods from its delegates (arguably)</span></p></li></ol><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">An Outline - The Emissary</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In the following, I will present an outline to tackle the problem. In order to de-bikeshed the discussion, I will introduce a new keyword placeholder called “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">” which is very unlikely ever to be used in a real implementation. This word could later be replaced by “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">delegator</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">” or any other descriptive word suitable for the purpose or perhaps even an existing keyword.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> An </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class has many similarities to a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">record</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class and can be used as shown in the example below:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public emissary Bazz(Foo foo, Bar bar);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bazz</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class has two delegates (</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Foo</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bar</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">) and consequently an equivalent desugared class is created having two private final fields:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">private final Foo foo;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">private final Bar bar;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">An </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class is also provided with a constructor. This process could be the same as for records with canonical and compact constructors:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public final class Bazz {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Foo foo;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Bar bar;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public Bazz(Foo foo, Bar bar) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this.foo = foo;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this.bar = bar;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It also makes the emissary class implement </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Foo</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bar</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Because of this, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Foo</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bar</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> must be interfaces and not abstract or concrete classes. (In a variant of the current proposal, the implementing interfaces could be explicitly declared).</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public final class Bazz implements Foo, Bar {</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Foo foo;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Bar bar;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public Bazz(Foo foo, Bar bar) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this.foo = foo;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this.bar = bar;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Now, in order to continue the discussion, we need to describe the example classes </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Foo</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bar</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> a bit more which is done hereunder:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public interface Foo() {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> void f();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public interface Bar() {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> void b();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">By declaring an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class we, unsurprisingly, also get the actual delegation methods so that </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bazz</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will actually implement its interfaces </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Foo</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bar</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public final class Bazz implements Foo, Bar {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Foo foo;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private final Bar bar;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public Bazz(Foo foo, Bar bar) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this. Foo = foo;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this.bar = bar;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> void f() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> foo.f();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> void b() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> bar.b();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">If the delegates contain methods with the same signature, these would have to be explicitly “de-ambigued”, for example in the same way as default methods in interfaces. Hence, if </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Foo</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bar</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> both implements </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">c()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> then </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bazz</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> needs to explicitly declare </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">c()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> to provide reconciliation. One example of this is shown here where both delegates are invoked:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">@Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">void c() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> foo.c();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> bar.c();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Nothing prevents us from adding additional methods by hand, for example, to implement additional interfaces the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class explicitly implements but that is not covered by any of the delegates.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It is also worth noting that the proposed </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> classes should </span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">not</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> get a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">hashCode()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">equals()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> or </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">toString()</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> methods generated. If they did, they would violate property C and leak information about its delegates. For the same reason, there should be no de-constructor for an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class as this bluntly would break encapsulation. Emissary classes should not implement </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Serializable</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and the likes by default.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">An </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class, just like a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">record</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class, is immutable (or at least unmodifiable and therefore shallowly immutable) and is hence thread-safe if all the delegates are.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Finally, an emissary class would extend </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">java.lang.Emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, a new proposed abstract class similar to </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">java.lang.Enum</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">java.lang.Record</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Comparing Record with Emissary</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Comparing the existing </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">record</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and the proposed </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> classes yield some interesting facts:</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">record</span></h3><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Provides a generated hashCode() method</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Provides a generated equals() method</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Provides a generated toString() method</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Provides component getters</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Cannot declare instance fields other than the private final fields which correspond to components of the state description</span></p></li></ul><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span></h3><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Does </span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">not</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> provide a generated hashCode() method</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Does </span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">not</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> provide a generated equals() method</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Does </span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">not</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> provide a generated toString() method</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Provides delegating methods</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Implements delegates (in one variant)</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Can declare additional final instance fields other than the private final fields which correspond to delegates</span></p></li></ul><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">both </span></h3><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">A private final field for each component/delegate of the state description</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">A public constructor, whose signature is the same as the state/delegate description, that initializes each field from the corresponding argument; (canonical constructor and compact constructor)</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Gives up the ability to decouple API from representation</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Implicitly final, and cannot be abstract (ensuring immutability)</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Cannot extend any other class (ensures immutability)</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Extends a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">java.lang</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class other than </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Object</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p></li><li aria-level="1" dir="ltr" style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Can declare additional methods not covered by the properties/delegates</span></p></li></ul><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Anticipated Use Cases</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Here are some use cases of the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class:</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Composition</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Providing an Implementation for one or several interfaces using composition:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public emissary FooAndBar(Foo foo, Bar bar);</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Encapsulation</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Encapsulating an existing instance of a class, hiding the details of the actual implementation:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private emissary EncapsulatedResultSet(ResultSet resultSet);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> …</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> ResultSet rs = stmt.executeQuery(query);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> return new EncapsulatedResultSet(rs);</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Disallow down-casting</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Disallow the down-casting of an instance. I.e. an emissary class implements a restricted sub-set of its delegate’s methods where the non-exposed methods cannot be invoked via casting or reflection. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">String</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> implements </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CharSequence</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and in the example below, we provide a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">String</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> viewed as a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CharSequence</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> whereby we cannot down-cast the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CharSequence</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> wrapper back to a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">String</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private emissary AsCharSequence(CharSequence s);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> return new AsCharSequence(“I am a bit incognito.”);</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Services and Components</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Providing an implementation of an interface that has an internal implementation. The internal component package is typically not exported in the module-info file:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public emissary MyComponent(MyComponent comp) {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public MyComponent() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this(new InternalMyComponentImpl());</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> // Optionally, we may want to hide the public </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> // constructor</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private MyComponent(MyComponent comp) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this.comp = comp;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> } </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> MyComponent myComp = ServiceLoader.load(MyComponent.class)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> .iterator()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> .next();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Note: If </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">InternalMyComponentImpl</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is composed of an internal base class, contains annotations, has non-public methods, has fields etc. These will be completely hidden from direct discovery via reflection by the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">emissary</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class and under JPMS, it will be completely protected from deep reflection. </span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Comparing Two ResultSet Delegators</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Comparison between two classes delegating a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ResultSet</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">:</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Emissary Class</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// Using an emissary class. A one-liner</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public emissary EncapsulatedResultSet(ResultSet resultSet);</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 12pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">IDE Generation</span></h3><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// Using automatic IDE delegation. About 1,000 lines!</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public final class EncapsulatedResultSet implements ResultSet {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> private final ResultSet delegate;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public EncapsulatedResultSet(ResultSet delegate) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> this.delegate = delegate;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> @Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> public boolean next() throws SQLException {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> return delegate.next();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> // About 1000 additional lines are not shown here for brevity…</span></p><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Conclusions</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">We may conceptually reuse </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">record</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> classes for providing semantic composition and delegation support in the Java language. This would greatly reduce the language ceremony needed for these kinds of constructs and would very likely nudge developers towards using composition just like </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">record</span><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> classes nudged developers towards immutability. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The scientific field of composition and delegation and what is related to is much bigger than indicated in this article. Further studies are needed before arriving at a concrete proposal. Perhaps this is just a part of something bigger?</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Language support for composition and delegation in some form would make Java an even better language in my opinion.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">References</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[Bettini08]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bettini, Lorenzo. “Typesafe dynamic object delegation in class-based languages”, PPPJ '08: Proceedings of the 6th international symposium on Principles and practice of programming in Java, September 2008, Pages 171–180, </span><a href="https://doi.org/10.1145/1411732.1411756" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://doi.org/10.1145/1411732.1411756</span></a></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[Kabanov11]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kabanov, Jevgeni. “On designing safe and flexible embedded DSLs with Java 5”, Science of Computer Programming, Volume 76, Issue 11, November 2011 pp 970–991, </span><a href="https://doi.org/10.1016/j.scico.2010.04.005" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://doi.org/10.1016/j.scico.2010.04.005</span></a></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[Bloch18]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Source Sans Pro", sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Bloch, Joshua., Effective Java, Third Edition, ISBN 0-13-468599-7, 2018</span></p><br /><br /><br /></span>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0tag:blogger.com,1999:blog-4815481734454081491.post-38607494720067427182022-01-07T06:34:00.001-08:002022-01-07T06:34:06.904-08:00Java: How Object Reuse Can Reduce Latency and Improve Performance<p> </p><span id="docs-internal-guid-29f6b80c-7fff-6eef-24da-d51e4c2624c9" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 26pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Java: How Object Reuse Can Reduce Latency and Improve Performance</span></h1><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Become familiar with the art of object reuse by reading this article and learn the pros and cons of different reuse strategies in a multi-threaded Java application. This allows you to write more performant code with less latency.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">While the use of objects in object-oriented languages such as Java provides an excellent way of abstracting away complexity, frequent object creation can come with downsides in terms of increased memory pressure and garbage collection which will have an adverse effect on applications’ latency and performance. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Carefully reusing objects provides a way to maintain performance while keeping most parts of the intended level of abstraction. This article explores several ways to reuse objects.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Problem</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">By default</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, the JVM will allocate new objects on the heap. This means these new objects will accumulate on the heap and the space occupied will eventually have to be reclaimed once the objects go out of scope (i.e. are not referenced anymore) in a process called “Garbage Collection” or GC for short. As several cycles with creating and removing objects are passed, memory often gets increasingly fragmented.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">While this works fine for applications with little or no performance requirements, it becomes a significant bottleneck in performance-sensitive applications. To make things worse, these problems are often exacerbated in server environments with many CPU cores and across NUMA regions.</span></p><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Memory Access Latencies</span></h3><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Accessing data from main memory is relatively slow (around 100 cycles, so about 30 ns on current hardware compared to sub ns access using registers) especially if a memory region has not been accessed for long (leading to an increased probability for a TLB miss or even a page fault). Progressing towards more localized data residing in L3, L2, L1 CPU caches down to the actual CPU registers themselves, latency improves by orders of magnitude. Hence, it becomes imperative to keep a small working set of data.</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Consequences of Memory Latencies and Dispersed Data</span></h3><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As new objects are created on the heap, the CPUs have to write these objects in memory locations inevitably located farther and farther apart as memory located close to the initial object becomes allocated. This might not be a far-reaching problem during object creation as cache and TLB pollution will be spread out over time and create a statistically reasonably evenly distributed performance reduction in the application. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">However, once these objects are to be reclaimed, there is a memory access “storm” created by the GC that is accessing large spaces of unrelated memory over a short period of time. This effectively invalidates CPU caches and saturates memory bandwidth which results in significant and non-deterministic application performance drops.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">To make things worse, if the application mutates memory in a way that the GC cannot complete in a reasonable time, some GCs will intervene and stop all application threads so it can complete its task. This creates massive application delays, potentially in the seconds or even worse. This is referred to as “stop-the-world collections”.</span></p><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Poppins, sans-serif; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Improved GCs</span></h3><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In recent years, there has been a significant improvement in GC algorithms that can mitigate some of the problems described above. However, fundamental memory access bandwidth limitations and CPU cache depletion problems still remain a factor when creating massive amounts of new objects.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Reusing Objects is Not Easy</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Having read about the issues above, it might appear that reusing objects is a low-hanging fruit that can be easily picked at will. As it turns out, this is not the case as there are several restrictions imposed on object reuse.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">An object that is immutable can always be reused and handed between threads, this is because its fields are final and set by the constructor which ensures complete visibility. So, reusing immutable objects is straightforward and almost always desirable, but immutable patterns can lead to a high degree of object creation.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">However, once a </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">mutable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instance is constructed, Java’s memory model mandates that normal read and write semantics are to be applied when reading and writing normal instance fields (i.e. a field that is not </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">volatile</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">). Hence, these changes are only guaranteed to be visible to the same thread writing the fields. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Hence, contrary to many beliefs, creating a POJO, setting some values in one thread and handing that POJO off to another thread will simply not work. The receiving thread might see no updates, might see partial updates (such as the lower four bits of a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> were updated but not the upper ones) or all updates. To make thighs worse, the changes might be seen 100 nanoseconds later, one second later or they might never be seen at all. There is simply no way to know. </span></p><br /><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Various Solutions</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">One way to avoid the POJO problem is to declare primitive fields (such as </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> fields) </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">volatile</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and use atomic variants for reference fields. Declaring an array as </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">volatile</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> means only the reference itself is volatile and does not provide volatile semantics to the elements. This can be solved but the general solution is outside the scope of this article although the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Atomic*Array</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> classes provide a good start. Declaring all fields </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">volatile</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and using concurrent wrapper classes may incur some performance penalty.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Another way to reuse objects is by means of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ThreadLocal</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> variables which will provide distinct and time-invariant instances for each thread. This means normal performant memory semantics can be used. Additionally, because a thread only executes code sequentially, it is also possible to reuse the same object in unrelated methods. Suppose a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">StringBuilder</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is needed as a scratch variable in a number of methods (and then reset the length of the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">StringBuilder</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> back to zero between each usage), then a </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ThreadLocal</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> holding the very same instance for a particular thread can be reused in these unrelated methods (provided no method calls a method that shares the reuse, including the method itself). Unfortunately, the mechanism around acquiring the ThreadLocal’s inner instance creates some overhead. There are a number of other culprits associated with the use of code-shared </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ThreadLocal</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> variables making them:</span></p><br /><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Difficult to clean up after use.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Susceptible to memory leaks.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Potentially unscalable. Especially because Java’s upcoming virtual thread feature promotes creating a massive amount of threads.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Effectively constituting a global variable for the thread.</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Also, it can be mentioned that a thread context can be used to hold reusable objects and resources. This usually means that the thread context will somehow be exposed in the API but the upshot is that it provides fast access to thread reused objects. Because objects are directly accessible in the thread context, it provides a more straightforward and deterministic way of releasing resources. For example, when the thread context is closed. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Lastly, the concept of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ThreadLocal</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and thread context can be mixed providing an untainted API while providing simplified resource cleaning thereby avoiding memory leaks.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">It should be noted that there are other ways to ensure memory consistency. For example, using the perhaps less known Java class </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Exchanger</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. The latter allows the exchange of messages whereby it is guaranteed that all memory operations made by the from-thread prior to the exchange happen-before any memory operation in the to-thread.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Yet another way is to use open-source </span><a href="https://github.com/OpenHFT/Chronicle-Queue" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> which provides an efficient, thread-safe, object creation-free means of exchanging messages between threads. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In Chronicle Queue, messages are also persisted, making it possible to replay messages from a certain point (e.g. from the beginning of the queue) and to reconstruct the state of a service (here, a thread together with its state is referred to as a service). If an error is detected in a service, then that error state can be re-created (for example in debug mode) simply by replaying all the messages in the input queue(s). This is also very useful for testing whereby a number of pre-crafted queues can be used as test input to a service.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Higher order functionality can be obtained by composing a number of simpler services, each communicating via one or more Chronicle Queues and producing an output result, also in the form of a Chronicle Queue. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The sum of this provides a completely deterministic and decoupled event-driven microservice solution.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Reusing Objects in Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In </span><a href="http://minborgsjavapot.blogspot.com/2021/12/java-creating-terabyte-sized-queues.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">a previous article</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">open-source Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> was benchmarked and demonstrated to have high performance. One objective of this article is to take a closer look at how this is possible and how object reuse works under the hood in Chronicle Queue (using version 5.22ea6). </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As in the previous article, the same simple data object is used:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class MarketData extends SelfDescribingMarshallable {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int securityId;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> long time;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float last;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float high;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float low;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Getters and setters not shown for brevity</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The idea is to create a top-level object that is reused when appending a large number of messages to a queue and then analyse internal object usage for the entire stack when running this code:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final MarketData marketData = new MarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ChronicleQueue q = ChronicleQueue</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .single("market-data");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ExcerptAppender appender = q.acquireAppender();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (long i = 0; i < 1e9; i++) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> try (final DocumentContext document =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> appender.acquireWritingDocument(false)) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> document</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .wire()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .bytes()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .writeObject(MarketData.class, </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> MarketDataUtil.recycle(marketData));</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Since Chronicle Queue is serializing the objects to memory-mapped files, it is important that it does not create other unnecessary objects for the performance reasons stated above.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Memory Usage</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The application is started with the VM option “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">-verbose:gc”</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> so that any potential GCs are clearly detectable by observing the standard output. Once the application starts, a histogram of the most used objects are dumped after inserting an initial 100 million messages:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">pemi@Pers-MBP-2 queue-demo % jmap -histo 8536</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> num #instances #bytes class name</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">----------------------------------------------</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 1: 14901 75074248 [I</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 2: 50548 26985352 [B</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 3: 89174 8930408 [C</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 4: 42355 1694200 java.util.HashMap$KeyIterator</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 5: 56087 1346088 java.lang.String</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">…</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">2138: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Total 472015 123487536</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">After the application appended about 100 million additional messages some seconds later, a new dump was made:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">pemi@Pers-MBP-2 queue-demo % jmap -histo 8536</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> num #instances #bytes class name</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">----------------------------------------------</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 1: 14901 75014872 [I</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 2: 50548 26985352 [B</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 3: 89558 8951288 [C</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 4: 42355 1694200 java.util.HashMap$KeyIterator</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> 5: 56330 1351920 java.lang.String</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">…</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">2138: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Total 473485 123487536</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, there was only a slight increase in the number of objects allocated (around 1500 objects) indicating </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">no object allocation was made per message sent</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. No GC was reported by the JVM so no objects were collected during the sampling interval.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Designing such a relatively complex code path without creating any object while considering all the constraints above is of course non-trivial and indicates that the library has reached a certain level of maturity in terms of performance.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Profiling Methods</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Profiling methods called during execution reveals Chronicle Queue is using </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ThreadLocal</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> variables:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 151px; overflow: hidden; width: 624px;"><img height="151" src="https://lh6.googleusercontent.com/n-SAje3S-Va5s5HOqNcLZ8oGk0c9FCVN6VY1-k26cIi_f78W46C0Wd4RR0qfmsY3TGp-_O0rCJsU4y0Oh2uFrlzGVBOm1b41Fo0I_58-dHiKfO-Ol1_9LAlMM-KzOXCnwAhgCqc" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">It spends about 7% of its time looking up thread-local variables via the</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ThreadLocal$ThreadLocalMap.getEntry(ThreadLocal)</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> method but this is well worth its effort compared to creating objects on the fly. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, Chronicle Queue spends most of its time accessing field values in the POJO to be written to the queue using Java reflection. Even though it is a good indicator that the intended action (i.e. copying values from a POJO to a Queue) appears somewhere near the top, there are ways to improve performance even more by providing hand-crafted methods for serialization substantially reducing execution time. But that is another story.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">What’s Next?</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In terms of performance, there are other features such as being able to isolate CPUs and lock Java threads to these isolated CPUs, substantially reducing application jitter as well as writing custom serializers.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Finally, there is an enterprise version with replication of queues across server clusters paving the way towards high availability and improved performance in distributed architectures. The enterprise version also includes a set of other features such as encryption, time zone rolling, and asynchronous message handling.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue (open-source)</span><span style="color: black; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></a><a href="https://chronicle.software/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle homepage</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/products/queue-enterprise/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue Enterprise</span></a></p><br /></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" />Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-80953218210189006172021-12-30T02:04:00.005-08:002021-12-30T02:04:41.928-08:00Java: Creating Terabyte Sized Queues with Low-Latency<p><span style="caret-color: rgb(0, 0, 0); font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Queues are often fundamental components in software design patterns. But, what if there are millions of messages received every second and multi-process consumers need to be able to read the complete ledger of all messages? Java can only hold so much information before the heap becomes a limiting factor with high-impacting garbage collections as a result, potentially preventing us from fulfilling targeted SLAs or even halting the JVM for seconds or even minutes.</span></p><span id="docs-internal-guid-6fe2a8e2-7fff-b93b-4833-0341bc063f2c" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This article covers how to create huge persisted queues while retaining predictable and consistent low latency using </span><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">open-source Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Application</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this article, the objective is to maintain a queue of objects from market data feeds (e.g. the latest price for securities traded on an exchange). Other business areas such as sensory input from IOT devices or reading crash-recording information within the automotive industry could have been chosen as well. The principle is the same.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">To start with, a class holding market data is defined:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class MarketData extends SelfDescribingMarshallable {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int securityId;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> long time;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float last;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float high;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float low;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Getters and setters not shown for brevity</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Note: In real-world scenarios, great care must be taken when using </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">float</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">double</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for holding monetary values as this could otherwise cause rounding problems [Bloch18, Item 60]. However, in this introductory article, I want to keep things simple.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">There is also a small utility function </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketDataUtil::create</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> that will create and return a new random </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> object when invoked:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">static MarketData create() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> MarketData marketData = new MarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int id = ThreadLocalRandom.current().nextInt(1000);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setSecurityId(id);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float nextFloat = ThreadLocalRandom.current().nextFloat();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float last = 20 + 100 * nextFloat;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLast(last);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setHigh(last * 1.1f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLow(last * 0.9f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setTime(System.currentTimeMillis());</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return marketData;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Now, the objective is to create a queue that is durable, concurrent, low-latency, accessible from several processes and that can hold billions of objects.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Naïve Approach</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Armed with these classes, the naïve approach of using a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ConcurrentLinkedQueue</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> can be explored:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final Queue<MarketData> queue = new ConcurrentLinkedQueue<>();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (long i = 0; i < 1e9; i++) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> queue.add(MarketDataUtil.create());</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This will fail for several reasons:</span></p><br /><ol style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ConcurrentLinkedQueue</span><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> will create a wrapping Node for each element added to the queue. This will effectively double the number of objects created.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Objects are placed on the Java heap, contributing to heap memory pressure and garbage collection problems. On my machine, this led to my entire JVM becoming unresponsive and the only way forward was to kill it forcibly using “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">kill -9</span><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">”.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The queue cannot be read from other processes (i.e. other JVMs).</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Once the JVM terminates, the content of the queue is lost. Hence, the queue is not durable.</span></p></li></ol><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Looking at various other standard Java classes, it can be concluded that there is no support for large persisted queues.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="display: inline-block; position: relative; width: 100px;"></span></span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Using Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue is an open-source library and is designed to meet the requirements set forth above. Here is one way to set it up and use it:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final MarketData marketData = new MarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ChronicleQueue q = ChronicleQueue</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .single("market-data");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ExcerptAppender appender = q.acquireAppender();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (long i = 0; i < 1e9; i++) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> try (final DocumentContext document =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> appender.acquireWritingDocument(false)) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> document</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .wire()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .bytes()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .writeObject(MarketData.class, </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> MarketDataUtil.recycle(marketData));</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Using a MacBook Pro 2019 with a 2.3 GHz 8-Core Intel Core i9, north of 3,000,000 messages per second could be inserted using only a single thread. The queue is persisted via a memory-mapped file in the given directory “market-data”. One would expect a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> object to occupy 4 (</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securityId) + 8 (</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> time) + 4*3 (</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">float</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> last, high and low) = 24 bytes at the very least.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In the example above, 1 billion objects were appended causing the mapped file to occupy 30,148,657,152 bytes which translates to about 30 bytes per message. In my opinion, this is very efficient indeed.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, a single </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instance can be reused over and over again because Chronicle Queue will flatten out the content of the current object onto the memory mapped file, allowing object reuse. This reduces memory pressure even more. This is how the recycle method works:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">static MarketData recycle(MarketData marketData) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final int id = ThreadLocalRandom.current().nextInt(1000);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setSecurityId(id);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final float nextFloat = ThreadLocalRandom.current().nextFloat();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final float last = 20 + 100 * nextFloat;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLast(last);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setHigh(last * 1.1f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLow(last * 0.9f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setTime(System.currentTimeMillis());</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return marketData;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Reading from a Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Reading from a Chronicle Queue is straightforward. Continuing the example from above, the following shows how the first two </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects can be read from the queue:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ChronicleQueue q = ChronicleQueue</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .single("market-data");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ExcerptTailer tailer = q.createTailer();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (long i = 0; i < 2; i++) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> try (final DocumentContext document =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> tailer.readingDocument()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> MarketData marketData = document</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .wire()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .bytes()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .readObject(MarketData.class);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> System.out.println(marketData);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This might produce the following output:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">!software.chronicle.sandbox.queuedemo.MarketData {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securityId: 202,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> time: 1634646488837,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> last: 45.8673,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> high: 50.454,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> low: 41.2806</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">!software.chronicle.sandbox.queuedemo.MarketData {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securityId: 117,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> time: 1634646488842,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> last: 34.7567,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> high: 38.2323,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> low: 31.281</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">There are provisions to efficiently seek the tailer’s position, for example, to the end of the queue or to a certain index.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">What’s Next?</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">There are many other features that are out of scope for this article. For example, queue files can be set to roll at certain intervals (such as each day, hour or minute) effectively creating a decomposition of information so that older data may be cleaned over time. There are also provisions to be able to isolate CPUs and lock Java threads to these isolated CPUs, substantially reducing application jitter. </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Finally, there is an enterprise version with replication of queues across server clusters paving the way towards high availability and improved performance in distributed architectures. The enterprise version also includes a variety of other features such as encryption, time zone rolling and asynchronous appenders.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/open-hft/queue/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Open-source Chronicle Queue</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/products/queue-enterprise/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue Enterprise</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[Bloch18] Joshua Bloch, Effective Java, Third Edition, ISBN 0-13-468599-7, 2018 </span></p></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" />Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-48765294872406913442021-12-20T07:09:00.000-08:002021-12-20T07:09:25.935-08:00Java: Why a Set Can Contain Duplicate Elements<p> </p><span id="docs-internal-guid-4836dd2f-7fff-32c3-6b68-8ad624fcac92" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 26pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Java: Why a Set Can Contain Duplicate Elements</span></h1><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In low-latency applications, the creation of unnecessary objects is often avoided by reusing mutable objects to reduce memory pressure and thus the load on the garbage collector. This makes the application run much more deterministically and with much less jitter. However, care must be taken as to how these reused objects are used or else unexpected results might manifest themselves, for example in the form of a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Set</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> containing duplicate elements such as [B, B].</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">HashCode and Equals</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Java’s built-in </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> provides direct access to heap and native memory using 32-bit addressing. <a href="https://github.com/OpenHFT/Chronicle-Bytes">Chronicle Bytes</a> is a 64-bit addressing open-source drop-in replacement allowing much larger memory segments to be addressed. Both these types provide a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">hashCode()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">equals()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> method that depends on the byte contents of the objects’ underlying memory segment. While this can be useful in many situations, mutable objects like these should not be used in most of Java’s built-in </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Set</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> types and not as a key in most built-in </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Map</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> types.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Note: In reality, only 31 and 63 bits may be used as an effective address offset (e.g. using </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> offset parameters)</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Mutable Keys</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Below, a small code example is presented illustrating the problem with reused mutable objects. The code shows the use of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Bytes</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> but the very same problem exists for </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Set<CharSequence> set = new HashSet<>();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Bytes<?> bytes = Bytes.from("A");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">set.add(bytes);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// Reuse</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">bytes.writePosition(0);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// This mutates the existing object already</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// in the Set</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">bytes.write("B");</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// Adds the same Bytes object again but now under</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">// another hashCode()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">set.add(bytes);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">System.out.println(“set = “ + set);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The code above will first add an object with “A” as content meaning that the set contains [A]. Then the content of that existing object will be modified to “B”, which has the side effect of changing the set to contain [B] but will leave the old hash code value and the corresponding hash bucket unchanged (effectively becoming stale). Lastly, the modified object is added to the set again but now under another hash code leading to the previous entry for that very same object will remain!</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As a result, rather than the perhaps anticipated [A, B], this will produce the following output:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">set = [B, B]</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer and Bytes Objects as Keys in Maps</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">When using Java’s </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects or </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Bytes</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects as keys in maps or as elements in sets, one solution is using an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">IdentityHashMap</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Collections.newSetFromMap(new IdentityHashMap<>())</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> to protect against the mutable object peculiarities described above. This makes the hashing of the objects agnostic to the actual byte content and will instead use the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">System.identityHashCode()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> which never changes during the object's life.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Another alternative is to use a read-only version of the objects (for example by invoking </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer.asReadOnlyBuffer()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">) and refrain from holding any reference to the original mutable object that could provide a back-door to modifying the supposedly read-only object’s content.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Chronicle Map and Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><a href="https://github.com/OpenHFT/Chronicle-Map">Chronicle Map</a> is an open-source library that works a bit differently than the built-in Java Map implementations in the way that objects are serialized and put in off-heap memory, opening up for ultra-large maps that can be larger than the RAM memory allocated to the JVM and allows these maps to be persisted to memory-mapped files so that applications can restart much faster.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The serialization process has another less known advantage in the way that it actually allows reusable mutable objects as keys because the content of the object is copied and is effectively frozen each time a new association is put into the map. Subsequent modifications of the mutable object will therefore not affect the frozen serialized content allowing unrestricted object reuse.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Open-source <a href="https://github.com/OpenHFT/Chronicle-Queue">Chronicle Queue</a> works in a similar fashion and can provide queues that can hold terabytes of data persisted to secondary storage and, for the same reason as Chronicle Map, allows object reuse of mutable elements.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Conclusions</span><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">It is dangerous to use mutable objects, such as </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Bytes</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">ByteBuffer</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"> where the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">hashCode()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;"> depends on the content of the object, in some Map and Set implementations. </span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">An </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">IdentityHashMap </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">protects against corruption of maps and sets due to object mutation but makes these structures agnostic to the actual byte contents.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Read-only versions of previously modified memory segment objects might provide an alternate solution.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Chronicle Map and Chronicle Queue allow unrestricted use of mutable objects, opening up the path to deterministic low-latency operations.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle homepage</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Bytes" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Bytes on GitHub (open-source)</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Map" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Map on GitHub (open-source)</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Queue" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue on GitHub (open-source)</span></a></p></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" />Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-22474150522538605802021-12-08T03:31:00.005-08:002021-12-08T03:32:22.164-08:00Why General Inheritance is Flawed and How to Finally Fix it<p> </p><span id="docs-internal-guid-1ea243f2-7fff-592e-4d0d-75f8bff92d05" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 26pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Why General Inheritance is Flawed and How to Finally Fix it</span></h1><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">By leveraging composition and the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> keyword in the right way, you can improve your programming skills and become a better Java programmer. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">General inheritance, whereby a public class is extended over package boundaries, provides a number of challenges and drawbacks and should be avoided in almost all cases. Classes and methods can be made </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> meaning that subclassing is disallowed which effectively prevents inheritance. While this may sound like a strange thing to do in an object-oriented language like Java, it does carry significant benefits for a large number of class types.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">But, when should a class or method be </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and just why is general inheritance problematic?</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Immutable Classes</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Immutable classes are classes whose state can not be observed to change from the outside world. This gives immutable objects the advantage of being inherently thread-safe and they can be reused indefinitely.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Java’s built-in </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">String</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> class is an example of an immutable class. It </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">does</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> have an internal state that is very likely to change the first time </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">hashCode()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is called, but this internal state cannot be observed by an outside caller (unless resorting to reflection).</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Immutable classes shall always be declared </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or else subclasses could compromise the immutability contract, simply by adding and exposing a mutable state. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">For the sake of completeness, it is worth mentioning that an immutable class should declare all its fields as </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">private</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and ensure exclusive access to any mutable sub-component (such as an array), for example using defensive copying.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Non-instantiable Classes (aka Utility Classes)</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">A </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">non-instantiable class</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is often informally referred to as a “</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">utility class</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">” and contains only static methods (and perhaps static fields). Static methods are not class methods but rather global functions attached to a “carrier-class”. Ideally, non-instantiable classes should be immutable concerning their (static) state (if any).</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">These methods should be called using their carrier-class name followed by the method name (e.g. </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Collections.emptyList()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">). Subclassing a non-instantiable utility can result in non-intuitive behavior and is likely a source of confusion as the methods cannot be overridden anyhow, only replaced as illustrated hereunder:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class FooUtil {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> static void print() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> lower();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> static void lower() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> System.out.println("lower foo");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class BarUtil extends FooUtil {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> static void lower() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> System.out.println("lower bar");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Invoking </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BarUtil::print</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> will produce “lower foo” and not “lower bar” meaning that </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BarUtil::lower</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> did not override </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">FooUtil::lower</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. However, if </span><span style="font-family: "Courier New"; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BarUtil::lower</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> was called directly, it would have printed “lower bar”.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Therefore, non-instantiable classes should generally be declared </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As a side note, non-instantiable classes should have a single default constructor declared </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">private</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> to prevent instantiation of the non-instantiable class (as the name implies).</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Methods Called by a Constructor</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Methods called by a constructor of a class should always be final, either by declaring the entire class </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or by declaring these methods </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. Failure to do this may open up a leak of an object (e.g. “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">this</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">”) that is only partially initialized and thus is likely in an illegal state. Such a leak may, for example, occur by the not-yet-initialized instance registering itself with a listener. These errors are likely hard to identify if they make it out in the open.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">General Inheritance</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The use/non-use of general inheritance has sparked opinionated discussions for quite some time.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Back in the early days, inheritance was often thought to be </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">the</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> general way of code reuse. As it later turned out, inheritance outside a package could lead to unsatisfiable and erroneous behaviour unless special care is put into providing classes that are suitable to extend across package boundaries [Bloch18, Item18]. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Furthermore, general inheritance breaks encapsulation [Snyder80] because the superclass implementation might change over time which might cause a subclass to fail even though no changes were made. This problem might be avoided if one commits to never change the superclass, effectively making the superclass a large monolithic fossil API commitment for eternal times. In all fairness, this argument can also be raised against classes using composition even though there are fewer ways problems can leak into the code. So, this is not an argument for finalization but rather a more fundamental problem with code reuse.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Inheritance could produce unintended effects due to </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">self-use</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, whereby an overridable method calls another overridable method in the base class: Imagine a class that extends </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ArrayList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and that is supposed to keep track of the number of elements ever added to the class. If we override </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">add()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> bumping the counter by one and override </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">addAll(Collection)</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> adding </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Collection.size()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> to the counter after which the corresponding super method is called, then we are in for a surprise: </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Because </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ArrayList::addAll</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> happens to self-use </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ArrayList::add</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> to individually add the elements, additions via </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">addAll()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> will count twice. Furthermore, there is no guarantee that this behavior will stay the same over time unless it is documented. Maybe there will be a more performant way of bulk-adding elements in the future whereby elements are directly inserted in the backing array without calling </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">add()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">?</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Another common problem with self-use is when a subclass overrides a method that is supposed to call one or several other methods but the programmer forgets to call the super method. A related problem is the problem of deciding if an overriding method should call the super method at the beginning or at the end of the overridden method (or indeed somewhere in between). A solution to some of these problems could be to declare the top method </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> in the base class and provide overridable protected “hook methods” that can be overridden in a more controlled fashion. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">General inheritance also opens up potential security vulnerabilities: Suppose an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ArrayList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> was extended to ensure only objects fulfilling a certain predicate could be added (e.g. they must be in a valid state). Then, in a later release, a new way of adding elements was introduced via the base class </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">AbstractList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. This new way will now become visible in the supposedly safeguarded class, effectively providing a back-door for adding illegal objects to the list. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Another problem is “</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">propagating exposure”</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> as exemplified by </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Arrays.asList(“a”, “b”)</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> which returns a “fixed-size list” (but ought to return an unmodifiable </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and here an immutable </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> as the elements themselves are all immutable). As it turns out, elements in the returned </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> may now not only be replaced via an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Iterator</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> but also via the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List::replaceAll,</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">a method added in JDK 8 </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">after</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> the inception of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Arrays::asList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">An additional class of problems might arise if a subclass adds a new method to the ones of the base class. If at a later stage, a method with the same signature is added to the base class, then this method will be coincidentally overridden by the subclass. This is likely not the intended behavior at all. If a method with the same name and parameters are added but with a different return type, then the code will likely fail to compile. So in the general case, it is not possible to ever add methods in a non-final public class as there is no control of how the class is subclassed.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Yet another problem could be </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">incidental inheritance</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. The JDK itself has several problematic inheritances whereby classes were incidentally inherited because it was apparently “convenient“ and not because class </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">B</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> indeed </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">was</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> class </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">A</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. For example, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stack</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> extends the old </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Vector</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> class for no good principal reason. This prevents </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stack</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> from evolving to a more efficient and performant implementation.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">To summarize, a class that is supposed to be generally inherited is very hard to ever change and must [Bloch18, Item19]:</span></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Document its self-use of overridable methods</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Potentially providing hooks in the form of judiciously chosen protective methods</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Be accompanied by tests using subclasses</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Not provide a constructor that invokes overridable methods</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Not allow serialization to invoke overridable methods</span></p></li></ul><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Inheriting also creates constraints and problems if </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">hashCode()/equals()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> are overridden. If we have a base class called </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Fruit</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, then is an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Apple</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> with the same color as a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Pear</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> equal? Can an instance of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">SevilleOrange</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> ever be equal to a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">BergamontOrange</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instance? Generally, it is not easy to decide these kinds of questions. It is important to remember that any subclass should either override none of these methods or should override them both.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">It should be noted that exposing a public non-final class in a public API by definition means that it opens up for inheritance across package boundaries as user-land code can place extending classes in any packet. Since split packages are strongly discouraged or might even be entirely forbidden depending on the use of JPMS, subclassing such a class </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">implies</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> subclassing over package boundaries.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">One way of avoiding all these things is to declare classes </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and use composition instead of inheritance, effectively abandoning inheritance across packages. This often provides a much cleaner API whereby only interfaces can be exposed and concrete classes do not leak out in the API. This way, any superclass used is only package-private and can, by convention or definition, never be used externally.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Composition with delegation protects against most of the problems mentioned above including unintended self-use, security holes via extra methods in base classes, signature collisions, incidental inheritance, need of subclass testing, accidental leak of “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">this</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">” and many other problems. In the past, it was feared that this would lead to reduced performance but this is simply not the case.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Inheritance in Java is, for good reasons, restricted to one superclass which naturally limits the scalability of the concept. Composition, on the other hand, allows an arbitrary number of delegates to be used.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">A small drawback with composition could materialize in combination with the use of certain callbacks. However, this problem can be avoided if proper provisions are put in. In other words, if a component (used in composition) registers itself with a listener, then the listener will invoke the component itself and not the composing class.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Sealed Classes</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In more recent Java versions, the concept of sealed classes (</span><a href="https://openjdk.java.net/jeps/409" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">JEP 409</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">) was introduced. Before this, the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> keyword was a boolean property: either a class was extensible (within its declared access type) or it was not. Sealed classes introduce a more granular mechanism whereby it can be said that a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Fruit</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> can either be an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Apple</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Pear</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Orange</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> but nothing more. This is fundamentally a more generalized form of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. The amount of effort put into the Java languages with features like this indicates a class extensibility is an important property. Interestingly, a permitted class in a sealed interface </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">must</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> specify whether itself is </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">non-final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">permits</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> subsequent subclasses. </span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">API Commitments Imposed by Inheritance</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this article, the class </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stack</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> was mentioned as a failed inheritance implementation. It basically introduces the methods </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">push()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">pop()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">peek()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">empty()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">search()</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. But, as it inherits from </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Vector</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, we also get all the methods/classes from </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">AbstractList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">RandomAccess</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Cloneable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Serializable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">AbstractList</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, which in turn, inherits from </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">AbstractCollection</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> which implements </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Collection</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This increases the API weight by orders of magnitudes and I am perfectly certain the Java designers are regretting their incidental inheritance 25 years down the line. If </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stack</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> was just an interface and there was a static method available that provided a new empty </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Stack</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, things would look much better.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Classes that are </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Serializable</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or subject to other serialization mechanisms are often particularly problematic as the binary (or other) format more often than not limits the way implementations can ever evolve over time.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As seen above and in previous clauses,</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"> a public non-final class cannot ever change in many cases</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Should Inheritance Across Package Boundaries Ever be Used?</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This is a matter of opinion. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Many times, it is better to use composition. In simpler cases delivering functions to a concrete class’ constructor providing tailored functionality would be preferable over allowing subclassing and overriding methods. To give an example of this, instead of overriding a handler method, a method handler could be provided via the constructor to a non-extensible class.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">If, after very careful consideration, one arrives at the conclusion that one should provide an extensible class (across packages), then all the constraints above must be taken into careful consideration. Just allowing subclassing by default is a right-out mistake, particularly for library and API designers. Instead, classes should be marked </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> by default, and only after careful review and testing, opening up for subclassing could be regarded.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">A Final Note</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As I moved away from using inheritance across packages and switched to exposing just interfaces, many other advantages became apparent. It becomes much easier to keep internal considerations… well internal.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Composition whereby potentially several components can be used in a single class provides more code reuse capability than inheritance, albeit requiring a bit more code ceremony in the using class. It can also simplify testing of the code and provides better test coverage with much fewer and less brittle tests.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">It also fits very well with the module system (JPMS). Providing components as pure services, for example, using Java’s </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ServiceLoader</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, adds flexibility while minimizing the API footprint. This makes it easier to learn and use the API and provides much more flexibility to evolve libraries over time. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Finally, it all makes sense...</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">References</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[Bloch18]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Bloch, Joshua., Effective Java, Third Edition, ISBN 0-13-468599-7, 2018</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[Snyder80]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Snyder, Allan. “Encapsulation and Inheritance in Object-Oriented Programming Languages”. In Object-Oriented Programming Systems, Language and Applications Proceedings, 35-45, New-York, NY ACM Press.</span></p><br /></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" />Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-44891147632996832392021-12-02T00:45:00.002-08:002021-12-02T00:45:28.402-08:00Java: Creating Terabyte Sized Queues with Low-Latency<p><span style="caret-color: rgb(0, 0, 0); font-family: Poppins, sans-serif; font-size: 11pt; white-space: pre-wrap;">Queues are often fundamental components in software design patterns. But, what if there are millions of messages received every second and multi-process consumers need to be able to read the complete ledger of all messages? Java can only hold so much information before the heap becomes a limiting factor with high-impacting garbage collections as a result, potentially preventing us from fulfilling targeted SLAs or even halting the JVM for seconds or even minutes.</span></p><span id="docs-internal-guid-d68f19ad-7fff-9851-4c9e-4e840540c345" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This article covers how to create huge persisted queues while retaining predictable and consistent low latency using </span><a href="https://github.com/OpenHFT/Chronicle-Queue" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">open-source Chronicle Queue</span></a><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Application</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this article, the objective is to maintain a queue of objects from market data feeds (e.g. the latest price for securities traded on an exchange). Other business areas such as sensory input from IOT devices or reading crash-recording information within the automotive industry could have been chosen as well. The principle is the same.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">To start with, a class holding market data is defined:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class MarketData extends SelfDescribingMarshallable {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int securityId;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> long time;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float last;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float high;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float low;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Getters and setters not shown for brevity</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Note: In real-world scenarios, great care must be taken when using </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">float</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">double</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for holding monetary values as this could otherwise cause rounding problems [Bloch18, Item 60]. However, in this introductory article, I want to keep things simple.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">There is also a small utility function </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketDataUtil::create</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> that will create and return a new random </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> object when invoked:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">static MarketData create() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> MarketData marketData = new MarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int id = ThreadLocalRandom.current().nextInt(1000);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setSecurityId(id);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float nextFloat = ThreadLocalRandom.current().nextFloat();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> float last = 20 + 100 * nextFloat;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLast(last);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setHigh(last * 1.1f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLow(last * 0.9f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setTime(System.currentTimeMillis());</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return marketData;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Now, the objective is to create a queue that is durable, concurrent, low-latency, accessible from several processes and that can hold billions of objects.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Naïve Approach</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Armed with these classes, the naïve approach of using a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ConcurrentLinkedQueue</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> can be explored:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final Queue<MarketData> queue = new ConcurrentLinkedQueue<>();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (long i = 0; i < 1e9; i++) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> queue.add(MarketDataUtil.create());</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This will fail for several reasons:</span></p><br /><ol style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">ConcurrentLinkedQueue</span><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> will create a wrapping Node for each element added to the queue. This will effectively double the number of objects created..</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Objects are placed on the Java heap, contributing to heap memory pressure and garbage collection problems. On my machine, this led to my entire JVM becoming unresponsive and the only way forward was to kill it forcibly using “</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">kill -9</span><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">”.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The queue cannot be read from other processes (i.e. other JVMs).</span></p></li><li aria-level="1" dir="ltr" style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Once the JVM terminates, the content of the queue is lost. Hence, the queue is not durable.</span></p></li></ol><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Looking at various other standard Java classes, it can be concluded that there is no support for large persisted queues.</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="display: inline-block; position: relative; width: 100px;"></span></span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Using Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue is an open-source library and is designed to meet the requirements set forth above. Here is one way to set it up and use it:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final MarketData marketData = new MarketData();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ChronicleQueue q = ChronicleQueue</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .single("market-data");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ExcerptAppender appender = q.acquireAppender();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (long i = 0; i < 1e9; i++) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> try (final DocumentContext document =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> appender.acquireWritingDocument(false)) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> document</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .wire()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .bytes()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .writeObject(MarketData.class, </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> MarketDataUtil.recycle(marketData));</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Using a MacBook Pro 2019 with a 2.3 GHz 8-Core Intel Core i9, north of 3,000,000 messages per second could be inserted using only a single thread. The queue is persisted via a memory-mapped file in the given directory “market-data”. One would expect a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> object to occupy 4 (</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securityId) + 8 (</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> time) + 4*3 (</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">float</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> last, high and low) = 24 bytes at the very least.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In the example above, 1 billion objects were appended causing the mapped file to occupy 30,148,657,152 bytes which translates to about 30 bytes per message. In my opinion, this is very efficient indeed.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As can be seen, a single </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instance can be reused over and over again because Chronicle Queue will flatten out the content of the current object onto the memory mapped file, allowing object reuse. This reduces memory pressure even more. This is how the recycle method works:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">static MarketData recycle(MarketData marketData) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final int id = ThreadLocalRandom.current().nextInt(1000);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setSecurityId(id);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final float nextFloat = ThreadLocalRandom.current().nextFloat();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final float last = 20 + 100 * nextFloat;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLast(last);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setHigh(last * 1.1f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setLow(last * 0.9f);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> marketData.setTime(System.currentTimeMillis());</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return marketData;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Reading from a Chronicle Queue</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Reading from a Chronicle Queue is straightforward. Continuing the example from above, the following shows how the first two </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">MarketData</span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects can be read from the queue:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public static void main(String[] args) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ChronicleQueue q = ChronicleQueue</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .single("market-data");</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final ExcerptTailer tailer = q.createTailer();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> for (long i = 0; i < 2; i++) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> try (final DocumentContext document =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> tailer.readingDocument()) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> MarketData marketData = document</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .wire()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .bytes()</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> .readObject(MarketData.class);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> System.out.println(marketData);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">This might produce the following output:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">!software.chronicle.sandbox.queuedemo.MarketData {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securityId: 202,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> time: 1634646488837,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> last: 45.8673,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> high: 50.454,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> low: 41.2806</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">!software.chronicle.sandbox.queuedemo.MarketData {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securityId: 117,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> time: 1634646488842,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> last: 34.7567,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> high: 38.2323,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> low: 31.281</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">There are provisions to efficiently seek the tailer’s position, for example, to the end of the queue or to a certain index.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">What’s Next?</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">There are many other features that are out of scope for this article. For example, queue files can be set to roll at certain intervals (such as each day, hour or minute) effectively creating a decomposition of information so that older data may be cleaned over time. There are also provisions to be able to isolate CPUs and lock Java threads to these isolated CPUs, substantially reducing application jitter. </span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Finally, there is an enterprise version with replication of queues across server clusters paving the way towards high availability and improved performance in distributed architectures. The enterprise version also includes a variety of other features such as encryption, time zone rolling and asynchronous appenders.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Poppins, sans-serif; font-size: 18pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle homepage</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Queue" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue on GitHub (open-source)</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Queue#chronicle-queue-enterprise-edition" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Queue Enterprise information on GitHub</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">[Bloch18] Joshua Bloch, Effective Java, Third Edition, ISBN 0-13-468599-7, 2018 </span></p></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" />Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-3850759629333663812021-11-01T00:32:00.003-07:002021-11-01T00:32:24.859-07:00Did You Know You Can Create Mappers Without Creating Underlying Objects in Java?<p> <span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As most Java developers know, putting values in a Java Map (like a </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">HashMap</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">) involves creating a large number of auxiliary objects under the covers. For example, a </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">HashMap</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> with </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> keys and </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> values might, for each entry, create a wrapped </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Integer</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">, a wrapped </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Long</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> object and a </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Node</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> that holds the former values together with a hash value and a link to other potential </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Node</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects sharing the same hash bucket. Perhaps even more tantalizing is that a wrapped </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Integer</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> might be created</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"> each time the </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Map</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"> is queried!</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> For example, using the </span><span style="caret-color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Map::get</span><span style="caret-color: rgb(0, 0, 0); font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> operation.</span></p><span id="docs-internal-guid-44e6f44d-7fff-645b-8851-6d2dd40c3684" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">In this short tutorial, we will devise a way of creating an object-creation-free, light-weighted mapper with rudimentary lookup capability that is suitable for a limited number of associations. The mapper is first created and initialized, whereafter it can be queried. Interestingly, these mappers can also be serialized/deserialized and sent over the wire using </span><a href="https://github.com/OpenHFT" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle’s open-source libraries </span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">without incurring additional object creation.</span></p><br /><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Arial; font-size: 20pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Setting the Scene</span></h1><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Suppose we have a number of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Security</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects with an “id” field of type </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. We would like to create a reusable mapper for these objects allowing a number of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Security</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects to be looked up using the “id” field:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public final class Security extends SelfDescribingMarshallable {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private int id;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private long averagePrice;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private long count;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public Security(int id, long price, long count) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> this.id = id;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> this.averagePrice = price;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> this.count = count;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Getters, setters and toString() not shown for brevity</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">SelfDescribingMarshallable</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is basically a serialization marker.</span></p><h1 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 20pt;"><span style="font-family: Arial; font-size: 20pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Implementing an IntMapper</span></h1><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">We can now store these </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Security</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects in an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">IntMapper</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> containing the actual lookup method as shown hereunder:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class IntMapper<V> extends SelfDescribingMarshallable {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final List<V> values = new ArrayList<>();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> private final ToIntFunction<? super V> extractor;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public IntMapper(final ToIntFunction<? super V> extractor) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> this.extractor = Objects.requireNonNull(extractor);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public List<V> values() { return values; }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public IntStream keys() {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return values.stream().mapToInt(extractor);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public void set(Collection<? extends V> values) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> this.values.clear();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> this.values.addAll(values);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Sort the list in id order</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> this.values.sort(comparingInt(extractor));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public V get(int key) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int index = binarySearch(key);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> if (index >= 0)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return values.get(index);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> else</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return null;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // binarySearch() shown later in the article</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">That’s it! We have created a reusable mapper with no object creation overhead with reasonable query performance.</span></p><br /><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Using the Mapper</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Armed with the above classes, we can put together a small main method that demonstrates the use of the concept:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">public class SecurityLookup {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> public static void main(String[] args) {</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // These can be reused</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final Security s0 = new Security(100, 45, 2);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final Security s1 = new Security(10, 100, 42);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final Security s2 = new Security(20, 200, 13);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // This can be reused</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final List<Security> securities = new ArrayList<>();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securities.add(s0);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securities.add(s1);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> securities.add(s2);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> // Reusable Mapper</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> IntMapper<Security> mapper =</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> new IntMapper<>(Security::getId);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> mapper.set(securities);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> Security security100 = mapper.get(100);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> System.out.println("security100 = " + security100);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">As expected, the program will produce the following output when run:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">security100 = Security{id=100, averagePrice=45, count=2}</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Binary Search Method Implementation</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The binary search method used above might be implemented like this:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int binarySearch(final int key) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int low = 0;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int high = values.size() - 1;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> while (low <= high) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final int mid = (low + high) >>> 1;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> final V midVal = values.get(mid);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> int cmp = Integer.compare(</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> extractor.applyAsInt(midVal), key);</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> if (cmp < 0)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> low = mid + 1;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> else if (cmp > 0)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> high = mid - 1;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> else</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return mid;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> return -(low + 1);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> }</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Unfortunately, we cannot use </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Arrays::binarySearch</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Collections::binarySearch</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">. One reason is that methods like these would create additional objects upon querying.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Other Key Types</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">If we want to use other types like </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">CharSequence</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> or other reference objects, there is an overload of the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">comparing()</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> method that takes a custom comparator. This might look like the following in the case of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">CharSequence</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">values.sort(</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> comparing(Security::getId, CharSequenceComparator.INSTANCE));</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">More generally, if the key reference object is of type K, then the binary search method above can easily be modified to use an extractor of type </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Function<? super T, ? extends K></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> instead and an added </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Comparator<? super K></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> parameter.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">A complete example of a generic </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Mapper<K, V></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> is available </span><a href="https://github.com/OpenHFT/Chronicle-Wire/tree/ea/demo/src/main/java/run/chronicle/wire/demo/mapreuse" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">here</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Serializing Across the Wire</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Sending </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">IntMapper </span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">objects over the wire without object creation requires special care on the receiver side so that old </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Security</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects can be reused. This involves setting up a transient buffer that holds recycled </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Security</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">private final transient List<V> buffer = new ArrayList<>();</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">We also have to override the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">IntMapper::readMarshallable</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> method and include:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">wire.read("values").sequence(values, buffer, Security::new);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">The complete setup is outside the scope of this article.</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="display: inline-block; position: relative; width: 100px;"></span></span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Analysis: HashMap vs. IntMapper</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Looking at various properties of the two alternatives, we see the following:</span></p><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Arial; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Execution Performance</span></h3><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none; table-layout: fixed; width: 468pt;"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Operation</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">HashMap</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">IntMapper</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">put/add</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">O(1) < x < O(log(N)) (*)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">O(1) (**)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">sort</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">-</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">O(log(N))</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">get</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">O(1) < x < O(log(N)) (*)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">O(log(N))</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">(*) Depending on key distribution, size, load factor and associations made.</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">(**) There is no add method in the IntMapper, instead all values are added in a batch</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Arial; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Memory usage in Bytes</span></h3><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none; table-layout: fixed; width: 468pt;"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Operation</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">HashMap</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">IntMapper</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">put/add</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">48N (***)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0 (***)</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">get</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">16N (***)</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">(***): The figures above are under typical JVM use, excluding the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Security</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects themselves and excluding any backing array, both of which can be recycled between use.</span></p><br /><h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;"><span style="color: #434343; font-family: Arial; font-size: 14pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Object Allocation in objects</span></h3><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none; table-layout: fixed; width: 468pt;"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Operation</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">HashMap</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">IntMapper</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">put/add</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">2 * N</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0</span></p></td></tr><tr style="height: 0pt;"><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">get</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">N</span></p></td><td style="border: 1pt solid rgb(0, 0, 0); overflow-wrap: break-word; overflow: hidden; padding: 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Poppins, sans-serif; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">0</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">All the figures above are excluding the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;">Security</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; vertical-align: baseline; white-space: pre-wrap;"> objects themselves and excluding any backing array.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Resources</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://chronicle.software/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Software Home Page</span></a></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Wire" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Chronicle Wire on GitHub (open-source)</span></a></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/OpenHFT/Chronicle-Wire/tree/ea/demo/src/main/java/run/chronicle/wire/demo/mapreuse" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; text-decoration-line: underline; vertical-align: baseline; white-space: pre-wrap;">Complete source code for all examples in this article (open-source)</span></a></p></span><br class="Apple-interchange-newline" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;" />Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-78984944494088982882020-10-01T05:08:00.006-07:002020-10-21T06:46:41.471-07:00How to get Type-Safe and Intuitive Hibernate/JPA Queries by Leveraging Java Streams<p><em>A large proportion of Java database applications are using Hibernate/JPA to bridge the gap between Java and SQL. Until recently, we were forced to mix Java and JPQL or to use complex imperative criteria builders to create database queries. Both of these methods are inherently neither type-safe nor very intuitive.</em><br /></p><p><em>The newly launched </em><a href="https://www.github.com/speedment/jpa-streamer"><em>open-source library JPAstreamer</em></a><em> addresses these issues by allowing you to express Hibernate/JPA queries using Java Streams. This means we can avoid any impedance mismatches between JPQL/HQL and Java and get full type-safety. In this article, I will show you how to put Java Stream queries to work in your application using JPAstreamer.</em></p><h2>JPAstreamer in a nutshell</h2><p>As mentioned, <a href="http://jpastreamer.org">JPAstreamer </a>allows JPA queries to be expressed as standard Java Streams using short and concise, type-safe declarative constructs. This makes our code shorter, less complex, and easier to read and maintain. Best of all, we can stick to using only Java code without needing to mix it with SQL/JPQL or other language constructs/DSL. <br /></p><p>In short, we can query a database like this:<br /></p><pre class="language-java"><code>jpaStreamer.stream(Film.class)<br /> .sorted(Film$.length.reversed())<br /> .limit(15)<br /> .map(Film$.title)<br /> .forEach(System.out::println);<br /></code></pre><p>This prints the title of the 15 longest films in the database. </p><h3><strong>OSS License</strong> </h3><p>JPAstreamer is using the same license as Hibernate (LGPL). This makes it easy to use in existing Hibernate projects. JPAstreamer also works with other JPA providers such as EclipseLink, OpenJPA, TopLink etc.</p><h3>Installation</h3><p>Installing JPAstreamer entails just adding a single dependency in your Maven/Gradle configuration file as described <a href="https://jpastreamer.org/install">here</a>. For example, Maven users add the following dependency:<br /></p><pre class="language-xml"><code>
<dependency>
<groupId>com.speedment.jpastreamer</groupId>
<artifactId>jpastreamer-core</artifactId>
<version>0.1.8</version><br /> </dependency>
<br /></code></pre><p>Let’s have a look at how JPAstreamer fits in an existing application.</p><h2>Example Database and JPA Entities</h2><p>In the examples below, we are using JPAstreamer to query the “Sakila” example database that is available for download <a href="https://dev.mysql.com/doc/sakila/en/sakila-installation.html">directly from Oracle</a> or as a <a href="https://hub.docker.com/r/restsql/mysql-sakila/">Docker instance</a>.<br /></p><p>This is how you install and run the example database using Docker:<br /></p><pre class="language-xml"><code> <br />$ docker pull restsql/mysql-sakila<br />$ docker run -d --publish 3306:3306 --name mysqld restsql/mysql-sakila<br /></code></pre><p>We will also be relying on JPA entities like the Film-class partly shown here:</p><pre class="language-java"><code>@Entity<br />@Table(name = "film", schema = "sakila")<br />public class Film implements Serializable {<br /><br /> @Id<br /><br /> @GeneratedValue(strategy = GenerationType.IDENTITY)<br /> @Column(name = "film_id", nullable = false, updatable = false, columnDefinition = "smallint(5)")<br /> private Integer filmId;<br /><br /> @Column(name = "title", nullable = false, columnDefinition = "varchar(255)")<br /> private String title;<br /><br /> @Column(name = "description", nullable = false, columnDefinition = "text")<br /> private String description;<br /><br /> @ManyToMany(cascade = CascadeType.ALL)<br /> @JoinTable(<br /> name = "film_actor",<br /> joinColumns = @JoinColumn(name = "film_id") ,<br /> inverseJoinColumns = @JoinColumn(name = "actor_id") </code></pre><pre class="language-java"><code> )<br /> private List<Artist><actor> actors;<br /> ...<br />}<br /></actor></code></pre><p>The complete code in this article is open-sourced and available <a href="https://github.com/minborg/jpastreamer-examples/tree/master/newkidontheblock">here</a>. <br /></p><h2>JPAstreamer - Printing the Longest Films</h2><p>Here is a complete example of how we can use JPAstreamer to create a query that prints out the length and title of the 15 longest films in the database:<br /></p><pre class="language-java"><code>public class LongestFilms {<br />
public static void main(String[] args) {
<br /> final JPAStreamer jpaStreamer = JPAStreamer.of("sakila");
<br /> jpaStreamer.stream(Film.class)<br /> .sorted(Film$.length.reversed())<br /> .limit(15)<br /> .map(f -> String.format("%3d %s", f.getLength(), f.getTitle()))<br /> .forEach(System.out::println);</code></pre><pre class="language-java"><code><br /> jpaStreamer.close();<br /> }</code></pre><pre class="language-java"><code> }<br /><br /></code></pre><p>This will print:<br /></p><pre class="language-xml"><code><br />185 SOLDIERS EVOLUTION<br />185 GANGS PRIDE<br />185 SWEET BROTHERHOOD<br />185 CHICAGO NORTH<br />185 HOME PITY<br />185 POND SEATTLE<br />185 CONTROL ANTHEM<br />185 DARN FORRESTER<br />185 WORST BANGER<br />184 SMOOCHY CONTROL<br />184 SONS INTERVIEW<br />184 SORORITY QUEEN<br />184 MOONWALKER FOOL<br />184 THEORY MERMAID<br /></code></pre><br /><p>As can be seen, queries are simple, concise, completely type-safe and follow the Java Stream standard API. No need to learn new stuff.<br /></p><p>The code above will create the following SQL (shortened for brevity):</p><pre class="language-xml"><code>select<br /> film0_.film_id as film_id1_1_,<br /> film0_.length as length4_1_,<br /> film0_.title as title10_1_,<br /> /* more columns */<br />from<br /> film film0_ <br />order by<br /> film0_.length desc limit ?<br /></code></pre><p>This means that most of the Java stream is actually executed on the database side. It is only the map() and forEach() operations (which cannot easily be translated to SQL) that are executed in the JVM. This is really cool!<br /></p><h2>Pre-Joining Columns</h2><p>To avoid the “SELECT N + 1” problem, it is possible to configure streams to join in columns eagerly by providing a configuration object like this:<br /></p><pre class="language-java"><code>StreamConfiguration<film> configuration = StreamConfiguration.of(Film.class)<br /> .joining(Film$.actors)<br /> .joining(Film$.language);<br /><br />jpaStreamer.stream(configuration) <br /> .filter(Film$.rating.in("G", "PG"))<br /> .forEach(System.out::println);<br /></film></code></pre><p>This will create a Hibernate join under the hood and will only render a single SQL query where all the Film fields “List<Artist> artists” and “Language language” will be populated on the fly:<br /></p><pre class="language-xml"><code><br />select<br /> Film <br />from <br /> Film as Film <br />left join <br /> fetch Film.actors as generatedAlias0 <br />left join <br /> fetch Film.language as GeneratedAlias1<br />where <br /> Film.rating in (<br /> :param0, :param1<br /> )<br /></code></pre><h2>Conclusion</h2><p>In this article, I have shown how you can avoid impedance mismatches between JPQL/HQL in Hibernate/JPA using the open-source library JPAstreamer. The Stream API allows you to compose type-safe and expressive database queries in standard Java without compromising the application performance. </p><h2>Feedback<br /></h2><p>The background to JPAStreamer is that we have developed the stream-based ORM-tool <a href="http://www.speedment.com">Speedment</a>, and we have come across many developers that want to use Java streams but are constrained to use Hibernate in their applications. Therefore, we have now developed JPAstreamer, a JPA/Hibernate extension that handles Java Stream queries without the need to change the existing codebase. </p><p>Take JPAStreamer for a spin and let me know what you like/dislike by dropping a message on <a href="https://gitter.im/speedment/jpa-streamer">Gitter</a>!<br /></p><h2>Resources</h2><ul><li>GitHub:<a href="https://www.github.com/speedment/jpa-streamer"> github.com/speedment/jpa-streamer</a></li><li>Homepage:<a href="http://www.jpastreamer.org"> jpastreamer.org</a></li><li>Documentation: <a href="https://speedment.github.io/jpa-streamer/jpa-streamer/0.1.8/introduction/introduction.html">github.io/jpa-streamer</a></li><li>Gitter Support Chat for questions and feedback:<a href="https://gitter.im/speedment/jpa-streamer"> gitter.im/jpa-streamer</a></li></ul>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.14301959.1316495638211563 -157.29926949999998 65.752117236178847 -86.9867695tag:blogger.com,1999:blog-4815481734454081491.post-81446875448475573752020-09-24T05:47:00.004-07:002020-09-24T06:11:06.130-07:00Extend Hibernate to Handle Java Stream Queries<p><em>The Java Stream API released in Java 8 has proven itself to be an efficient, terse yet intuitive way of expressing application logic. The newly launched open-source project</em><a href="https://www.github.com/speedment/jpa-streamer"><em> JPAstreamer</em></a><em> allows you to express Hibernate or other JPA database queries using Java Streams. In this article, we will show you how to extend the API of your existing database applications to handle Stream queries in an instant. </em><br /></p><p>To quickly give you an idea of what JPAstreamer accomplish, we’ll start by showing you an example of a Stream operating on a database table that contains arbitrary users (with attributes including a first and last name): </p><pre class="language-java"><code>jpaStreamer.stream(User.class)
.filter(User$.firstName.startsWith(”A”)<br /> .sort(User$.lastName.reversed())<br /> .limit(10)<br /> .forEach(System.out::println);<br /></code></pre><p>This will print ten users with a first name that starts with the letter A sorted in reversed order based on their last names. Omitting the details (that are covered shortly), this demonstrates how the desired result set is easily described as a pipeline of Stream operators. <br /></p><p>On the surface, it may look as if the presented Stream would require every row in the User-table to be materialized in the JVM. Although, the Stream is actually optimized and rendered to JPA queries. Thus, the Stream queries are as performant as alternative approaches i.e. JPQL or Criteria Builder, but with the difference that JPAstreamer constitutes a streamlined and type-safe approach to expressing queries.</p><h3>How JPAstreamer Works</h3><p>JPAstreamer plugs into your application with the addition of a single dependency in your Maven/Gradle build. The specific dependency is described <a href="https://speedment.github.io/jpa-streamer/jpa-streamer/0.1.8/get-jpa-streamer/install-maven.html">here</a>. <br /></p><p>Like the well-known Java library Lombok, JPAstreamer uses an annotation processor to form a meta-model at compile time. It inspects any classes marked with the standard JPA annotation @Entity and for every entity Foo.class, a corresponding Foo$.class is generated. The generated classes represent entity attributes as Fields that are used to form predicates on the form User$.firstName.startsWith(”A”) that can be interpreted by JPAstreamer’s query optimizer. <br /></p><p>It is important to note that JPAstreamer does not alter or disturb the existing codebase, but simply extends the API to handle Java Stream queries from this point forward. Further, the meta-model is placed in “generated sources” located in the “target” folder and doesn’t need to be checked in with the source code nor tested.<br /></p><h3>Let’s Get Streaming </h3><p>We’ll now walk you through the easy process of setting up JPAstreamer in your database application. To follow along, your application must use Java 8 (or later) and Hibernate or another JPA provider that is responsible for object persistence (if you wish to use the Stream API without JPA, you are better off using the open-source Stream ORM <a href="https://www.github.com/speedment/speedment">Speedment</a>). <br /></p><p>As mentioned, installation simply entails adding a dependency (described <a href="https://speedment.github.io/jpa-streamer/jpa-streamer/0.1.7/get-jpa-streamer/install-maven.html">here</a>) to your Maven/Gradle build and rebuilding the application to generate the JPAstreamer meta-model. <br /></p><p>Once you’ve completed the simple set-up, you need to obtain an instance of JPAStreamer like so: <br /></p><pre class="language-java"><code>JPAStreamer jpaStreamer = JPAStreamer.of("db-name"); <br /></code></pre><p>You should replace the String ”db-name” with the name of the persistence unit you wish to query. Look it up in your JPA configuration-file (often named persistence.xml) under the tag <persistence-unit>.<br /></p><p>The JPAstreamer instance provides access to the method <em>.stream()</em> that accepts the name of the <em>Entity</em> you wish to Stream. To query the user table, you would simply type: <br /></p><pre class="language-java"><code>jpaStreamer.stream(User.class); <br /></code></pre><p>This returns a stream of all the user rows of type <em>Stream<User</em>>. With a Stream source at hand, you are free to add any Java Stream operations to form a pipeline through which the data will flow (data flowing is a conceptual image rather than an actual description of how the code executes). For example: <br /></p><pre class="language-java"><code>List<String><string> users = jpaStreamer.stream(User.class)
.filter(User$.age.greaterThan(20))<br /> .map(u -> u.getFirstName() + ” ” + u.getLastName())
</string></code> .collect(Collectors.toList); </pre><p>This Stream collects the name of users who reached the age of 20 in a List. User$ refers to the generated entity that is part of JPAstreamer’s meta-model. This entity is used to form predicates and comparators for operations such as <em>.filter()</em> and <em>.sort() </em>which are quickly composed leveraging code completion in modern IDEs. <br /></p><p>Here is another example that counts all the users who are from Germany and are named “Otto” using a combined predicate: <br /></p><pre class="language-java"><code>long count = jpaStreamer.stream(User.class)
.filter(User$.country.equal(”Germany”).and(User$.firstName.equal(”Otto”))<br /> .count(); <br /></code></pre><h3>Conclusion</h3><p>In this article, we have shown how you can integrate the open-source library JPAstreamer with Hibernate (or any JPA provider) to compose type-safe and expressive database queries as standard Java Streams. <br /></p><h3>Resources</h3><ul><li>GitHub: <a href="https://www.github.com/speedment/jpa-streamer">github.com/speedment/jpa-streamer</a></li><li>Homepage: <a href="http://www.jpastreamer.org">jpastreamer.org</a></li><li>Documentation: <a href="http://www.speedment.github.io/jpa-streamer">github.io/jpa-streamer</a></li><li>Gitter Support Chat:<a href="https://gitter.im/speedment/jpa-streamer">gitter.im/jpa-streamer</a></li></ul><h3>Author </h3><p>Per Minborg<br />Julia Gustafsson</p>Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0tag:blogger.com,1999:blog-4815481734454081491.post-48779255090115436602020-04-24T03:58:00.000-07:002020-04-24T03:58:38.043-07:00Java/Cloud: How to Quickly Create a Kubernetes-ready REST Microservice<h2>
Java/Cloud: How to Quickly Create a Kubernetes-ready REST Microservice </h2>
It is safe to say that the Microservice + Cloud combination is all the rage these days. Microservices are being developed more than ever, in turn resulting in an increase in the number of application deployments. During the past decade, containerization and orchestration tools such as Docker and Kubernetes were developed, making the microservice pattern really easy to adopt.<br />
<br />
This article will teach you how to generate a completely functional microservice with an exposed REST API capable of interacting with a MySQL database and deploy it to your local Kubernetes cluster. The learnings here can be applied to almost any database type like Oracle, SQL Server, DB2, and so on.<br />
<br />
If you ever get stuck during the article, feel free to refer to the final version of the source code, which can be found in this <a href="https://github.com/dekmm/speedment-spring-app-example" target="_blank">GitHub repository.</a><br />
<br />
<h3>
Speed(ment) is Key </h3>
As developers, one of the things we strive for in our everyday work is shorter development time.<br />
<br />
At this point, we can already identify two aspects of our microservice that will make our development time longer than needed:<br />
<br />
<ol>
<li>We need to create a persistence layer </li>
<li>We need to expose a REST API
</li>
</ol>
<br />
<br />
What if I were to tell you that a tool exists which can handle these things, without you having to write a single line of code?
<br />
<br />
<a href="http://www.speedment.com/initializer" target="_blank">Speedment</a> is a Java ORM Toolkit and Runtime designed to allow developers to create super fast applications super fast. Speedment uses the native Java Streams API for database interaction, making it extremely easy to use for newcomers, seasoned veterans and anyone that falls in between. Speedment comes with a graphical tool, giving developers the ability to generate a Java representation of their database within seconds.<br />
<br />
Furthermore, Speedment’s bundle system allows developers to easily expand the base functionality of the base Toolkit. One such enhancement is the Spring plugin which enables developers to generate a completely functional CRUD REST API in order to interact with their database.
<br />
<br />
In the remainder of the article, you will learn how to use the Speedment Tool to generate a working REST microservice and deploy it to a Kubernetes cluster. If you’re interested in Speedment as a whole, detailed documentation with examples can be found in the <a href="https://speedment.github.io/speedment-doc/" target="_blank">online manual</a>.
<br />
<br />
<h3>
Getting Started</h3>
<div>
Being distributed via Maven, Speedment is installation free but requires Java 8 or later. To get started, head over to the <a href="https://speedment.com/download/" target="_blank">Speedment Initializer</a> where you’ll be able to download a project template with all of the dependencies needed to create your microservice. These are the settings we will be using in the example:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5Q_N8tPzCt2otWZQnmoUTcYcTm-Jr8haLGgwYvmn01zizE_qq2ADfJ4dn_uYDgx77LZv1SS90LPGkwtEGF7hKOi_INLuzrvgD8ieWmHU0rpUxcIVsB2JVzHVhyphenhyphen6arqU4Mz4yK8Xv3J5w/s1600/Screenshot+2020-04-23+at+18.03.20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1128" data-original-width="944" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5Q_N8tPzCt2otWZQnmoUTcYcTm-Jr8haLGgwYvmn01zizE_qq2ADfJ4dn_uYDgx77LZv1SS90LPGkwtEGF7hKOi_INLuzrvgD8ieWmHU0rpUxcIVsB2JVzHVhyphenhyphen6arqU4Mz4yK8Xv3J5w/s400/Screenshot+2020-04-23+at+18.03.20.png" width="332" /></a></div>
<br />
If your setup is different, e.g. different database, make sure you apply the appropriate changes in the initializer.<br />
<br />
Once you’re done configuring the project, click the Download button and unpack the downloaded zip-file. To launch the Speedment Tool, execute the following command from a terminal:
<br />
<code><br />mvn speedment:tool </code><br />
<code><br /></code>
If this is your first time running the Speedment Tool, you’ll be asked to connect to your database. We’re running the vanilla MySQL <a href="https://dev.mysql.com/doc/index-other.html" target="_blank">Sakila sample database</a> on our local machine, so the auth information would look like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu7MSA_uEJ2LdhoJEAwogQW5c9dD_5GF8poa4nq7VGsomQZleMK-l7HdeyONoXOU1Tmve7rjdVBQ8_PEd0m-Eh26gl4CNeQ_cGoiQqTOcbTSpTw28wzBUSBh0onnLDu3WXnvwRKZPTf-0/s1600/Screenshot+2020-04-23+at+18.03.34.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="880" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu7MSA_uEJ2LdhoJEAwogQW5c9dD_5GF8poa4nq7VGsomQZleMK-l7HdeyONoXOU1Tmve7rjdVBQ8_PEd0m-Eh26gl4CNeQ_cGoiQqTOcbTSpTw28wzBUSBh0onnLDu3WXnvwRKZPTf-0/s320/Screenshot+2020-04-23+at+18.03.34.png" width="312" /></a></div>
<br />
Once you’ve filled in the required fields, click the Connect button. If the auth information you’ve provided was correct, you will be presented with the following screen:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP0bbymvW1zyjxV2wK42b7oyoIHg2rVfzYa5zmhbAmbOLtzFUMHj_ckvAfHXIRjmJaXE0-QLKeBZh6MC7xm-Pfhy9RJZZT87esevLYn6DZ4OvvnQeQItGIHyTW92A2Yx2AtvvAfIu3jws/s1600/Screenshot+2020-04-23+at+18.03.42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="762" data-original-width="1088" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP0bbymvW1zyjxV2wK42b7oyoIHg2rVfzYa5zmhbAmbOLtzFUMHj_ckvAfHXIRjmJaXE0-QLKeBZh6MC7xm-Pfhy9RJZZT87esevLYn6DZ4OvvnQeQItGIHyTW92A2Yx2AtvvAfIu3jws/s640/Screenshot+2020-04-23+at+18.03.42.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3 style="clear: both; text-align: left;">
Generating the Microservice</h3>
When you’ve connected to the database via the Speedment Tool, you can start configuring the various options that are available. There are a lot of options you can play around with, but for the purposes of this article, we will be focusing on the options that are needed to expose a REST API.
<br />
<br />
To enable REST API generation, click on the Project node in the tree view, and check the Enable REST option:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-tl6-qgrF1ytS28HHDyrpULYV5mdsbcU51exPxKPqnwCgYK1PkeL7-Xh41ZMbC6Ic2cND-FvlEjYiW9dUA-OQRqXyLemAN0OfTkvi2DR0zriDQq4KQsVi4NJ-A_vTTPjfLoe1fjt9LSQ/s1600/Screenshot+2020-04-23+at+18.03.50.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="912" data-original-width="1312" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-tl6-qgrF1ytS28HHDyrpULYV5mdsbcU51exPxKPqnwCgYK1PkeL7-Xh41ZMbC6Ic2cND-FvlEjYiW9dUA-OQRqXyLemAN0OfTkvi2DR0zriDQq4KQsVi4NJ-A_vTTPjfLoe1fjt9LSQ/s640/Screenshot+2020-04-23+at+18.03.50.png" width="640" /></a></div>
<br />
<br />
We’ve also enabled the Generate REST documentation option to automatically generate the OpenAPI documentation for our REST API. This option is not mandatory, but it will allow us to test our API more easily in the end.<br />
<br />
The next step is optional, but it will make our REST routes a bit more aesthetically pleasing. Head over to the database schema node in the tree view and set the value of REST Endpoint to a front slash (/). By default, the schema name is included in the generated REST routes and this modification removes it.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilQFpsglJAUOg9hOLb2cJG11tZCfb-A9kpb-OBJMUvjwy06Z6rVCWHQkVjfILNldDdaoqjiWlbCHK-f-QHi4T0u9s4Ie6xmYFC10ZXjRb6YpjUeJ0kD8Vmdbm-bO46UqHOw7ZJDWIoAYk/s1600/Screenshot+2020-04-23+at+18.03.56.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="934" data-original-width="1318" height="452" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilQFpsglJAUOg9hOLb2cJG11tZCfb-A9kpb-OBJMUvjwy06Z6rVCWHQkVjfILNldDdaoqjiWlbCHK-f-QHi4T0u9s4Ie6xmYFC10ZXjRb6YpjUeJ0kD8Vmdbm-bO46UqHOw7ZJDWIoAYk/s640/Screenshot+2020-04-23+at+18.03.56.png" width="640" /></a></div>
<br />
<br />
Next, we’re going to enable the generation of REST controllers for the following tables:
<br />
<ul>
<li>Actor
</li>
<li>Category
</li>
<li>Customer
</li>
<li>Film
</li>
<li>Staff
</li>
<li>Store
</li>
</ul>
<br />
The steps to enable the controller generation are identical regardless of the table. For that reason we will only demonstrate them on the Actor table.
<br />
<br />
Click the Actor table in the tree view and enable the Generate @RestController option. This, in turn, will enable several REST related options for that table. The options we are interested in, which you should enable, are:
<br />
<ul>
<li>REST Enable LIST
</li>
<li>REST Enable GET
</li>
<li>REST Enable CREATE
</li>
<li>REST Enable UPDATE
</li>
<li>REST Enable DELETE
</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaCUZsQOua49WragtOlnoVfrpdW_jzw_EwWrPIrQXuf2nLlOZLmGWYBrcQveqxmsvoJvcLOdA7obi8BDsQ4vG8lWEcOmKaveB7g_505QJCTMhFj_YDROXQCB6NvJ_ep_Btt9mlsALc_ww/s1600/Screenshot+2020-04-23+at+18.04.05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="934" data-original-width="1314" height="454" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaCUZsQOua49WragtOlnoVfrpdW_jzw_EwWrPIrQXuf2nLlOZLmGWYBrcQveqxmsvoJvcLOdA7obi8BDsQ4vG8lWEcOmKaveB7g_505QJCTMhFj_YDROXQCB6NvJ_ep_Btt9mlsALc_ww/s640/Screenshot+2020-04-23+at+18.04.05.png" width="640" /></a></div>
<br />
We will also rename the REST Endpoint from /actor to /actors (again only for aesthetic purposes). By default, the REST Endpoint is named the same as the table it is associated with. In our case, the renaming makes sense, because when we visit the /actors endpoint, a list of actors will be retrieved, rather than a single actor.
<br />
<br />
Go ahead and repeat these steps for the other tables listed above. After you’re done, click the Generate button. This will generate a Java representation of your database along with the necessary REST configurations and controllers.
<br />
<br />
<h3>
Running the Microservice
</h3>
<br />
If we were to run our application right now as it is, it will most likely crash. This is because we haven’t specified the password our application should use to connect to the database.
<br />
<br />
When we generated our application, a bunch of Speedment-specific application properties were exposed. One such property is the spring.speedment.password property, which we can use to set the password Speedment will use to connect to our database.
<br />
<br />
There are a couple of ways to specify application properties. We’re going to be defining them in the application.properties file, which you should create in your application’s resources folder.
<br />
<br />
This is what our application.properties file looks like:
<br />
<br />
# Application properties file - START
<br />
spring.application.name=speedment-spring-app
<br />
<br />
spring.speedment.password=sakila
<br />
# Application properties file - END
<br />
<br />
The default password for the Sakila database is sakila, but if your database has a different password, make sure those changes are reflected in the application.properties file.
<br />
<br />
Once we have everything configured, we can run our application. This is done by executing the following command from the project’s root folder:
<br />
<code><br />mvn spring-boot:run</code>
<br />
<br />
If you’ve enabled the Generate REST documentation option, you can visit <a href="http://localhost:8080/swagger-ui.html">http://localhost:8080/swagger-ui.html</a> to access the REST API documentation:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSrITAy2nxC0lr5KudsH3M89sWbC-xi_IPrOAOTUw3NtzjAVaTdSz-J6X90_Q5Sq7PrbRrcw_juIVjSH9yij9q_tA3ZbEcQEy5mpCKxsPgJI_Xsv7iUwGalRAYlfy4MucW9IyhIz0udYY/s1600/Screenshot+2020-04-23+at+18.04.13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="784" data-original-width="1348" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSrITAy2nxC0lr5KudsH3M89sWbC-xi_IPrOAOTUw3NtzjAVaTdSz-J6X90_Q5Sq7PrbRrcw_juIVjSH9yij9q_tA3ZbEcQEy5mpCKxsPgJI_Xsv7iUwGalRAYlfy4MucW9IyhIz0udYY/s640/Screenshot+2020-04-23+at+18.04.13.png" width="640" /></a></div>
<br />
<br />
You can execute your requests manually or directly from Swagger UI. If we were to visit <a href="http://localhost:8080/actors">http://localhost:8080/actors</a> in our browser, we should get a JSON response with a list of actors stored in our database:<br />
<pre class="xml" name="code">[
{
"actorId": 1,
"firstName": "PENELOPE",
"lastName": "GUINESS"
},
{
"actorId": 2,
"firstName": "NICK",
"lastName": "WAHLBERG"
},
{
"actorId": 3,
"firstName": "ED",
"lastName": "CHASE"
},
... TRUNCATED ...
]
</pre>
<h3>
Before Deployment</h3>
Before we start with the deployment process of our microservice, make sure you have the following dependencies installed on your local machine: Docker, kubectl, Minikube
and Skaffold.<br />
<br />
<h3>
Dockerizing our Microservice</h3>
Before we can actually deploy our microservice to a Kubernetes cluster, we need to convert it into a format that Kubernetes can actually work with. Kubernetes is a container orchestration tool, so this is where Docker comes in to aid us with the container creation process.
<br />
<br />
In the root of your project, create a Dockerfile with the following contents:
<br />
<br />
<pre class="xml" name="code">FROM openjdk:11-slim-buster
EXPOSE 8080
ARG JAR_LOCATION=target
ARG JAR_NAME=speedment-spring-app
ARG JAR_VERSION=1.0.0
ADD ${JAR_LOCATION}/${JAR_NAME}-${JAR_VERSION}.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.speedment.host=sakila"]
</pre>
The exported arguments (JAR_LOCATION, JAR_NAME, JAR_VERSION) may be different for your project, depending on the information you provided in the pom.xml file. From the root of your project, execute the following command:
<br />
<code><br />mvn install</code>
<br />
<br />
This will create a target folder with a JAR file containing your microservice. Make sure the name and the version of the file match with the information you put in the Dockerfile.
<br />
<br />
<h3>
Creating the Deployment Configurations
</h3>
<br />
We will be deploying two images to our Kubernetes cluster: the Sakila database and our microservice. The Sakila database already has a Docker image publicly available: restsql/mysql-sakila. However, we need to build an image for our microservice. This is where the Dockerfile we created earlier will come in handy. Later on, we will be using a tool called Skaffold to create an image for our microservice and use it in the deployment process.
<br />
<br />
Start by creating a folder called k8s in the root of your project. This is where you’ll store all of your Kubernetes <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" target="_blank">Deployment</a> and <a href="https://kubernetes.io/docs/concepts/services-networking/service/" target="_blank">Service</a> configurations. We will keep our microservice and database configurations separate, so create two folders called storage and app in the k8s folder.<br />
<div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZWV-vgx0zA0kuKcsYF7-Pf_1QdXoLvxEQ5REhbMg2z2DC0jNzbyECGGqYH603FXrN_14d1W3CMiyVlzoK_DUqIljA0CaEwZWpK5v7YT_oP_lLPsLT_PwdM6KEoiKXCbjRqwb-kosa7YA/s1600/Screenshot+2020-04-24+at+11.22.02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="140" data-original-width="274" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZWV-vgx0zA0kuKcsYF7-Pf_1QdXoLvxEQ5REhbMg2z2DC0jNzbyECGGqYH603FXrN_14d1W3CMiyVlzoK_DUqIljA0CaEwZWpK5v7YT_oP_lLPsLT_PwdM6KEoiKXCbjRqwb-kosa7YA/s200/Screenshot+2020-04-24+at+11.22.02.png" width="200" /></a></div>
<div>
<br />
<br />
We now proceed with the configurations for the Sakila database. In the storage folder, we will create two YAML files - sakila-deployment.yml and sakila-service.yml. The sakila-deployment.yml file will store our deployment configuration for the Sakila database. As this is not a Kubernetes tutorial we will only be providing the final configurations. This is what the sakila-deployment.yml file should look like in the end:
<br />
<br />
<br />
<pre class="xml" name="code">apiVersion: apps/v1
kind: Deployment
metadata:
name: sakila
labels:
storage: sakila
spec:
replicas: 1
selector:
matchLabels:
storage: sakila
template:
metadata:
labels:
storage: sakila
spec:
containers:
- name: sakila
image: restsql/mysql-sakila
ports:
- containerPort: 3306
</pre>
<br />
And this is the final sakila-service.yml file:
<br />
<br />
<pre class="xml" name="code">apiVersion: v1
kind: Service
metadata:
name: sakila
labels:
storage: sakila
spec:
selector:
storage: sakila
ports:
- name: database
port: 3306
targetPort: 3306
</pre>
The deployment and service configurations for our microservice are nearly identical. In the app folder, create a YAML file called speedment-spring-app-deployment.yml with the following contents:
<br />
<br />
<pre class="xml" name="code">apiVersion: apps/v1
kind: Deployment
metadata:
name: speedment-spring-app
labels:
app: speedment-spring-app
spec:
replicas: 1
selector:
matchLabels:
app: speedment-spring-app
template:
metadata:
labels:
app: speedment-spring-app
spec:
containers:
- name: speedment-spring-app
image: speedment-spring-app-example
ports:
- containerPort: 8080
</pre>
In the same folder create another YAML file called speedment-spring-app-service.yml with the following contents:
<br />
<br />
<pre class="xml" name="code">apiVersion: v1
kind: Service
metadata:
name: speedment-spring-app
spec:
selector:
app: speedment-spring-app
ports:
- name: http
port: 8080
targetPort: 8080
type: NodePort
</pre>
<br />
These are all of the configurations we need in order to deploy our database and application. After adding the deployment configurations, our file structure should look like this:<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw8HxgNEUya5b04bzkQODgA3MuvJfnSOV6R-Bw58ia1Nr73KpUhgT5HTRWnzcFFiZLYiHk_9qfI5Zh7oTAnL42pWl0voNulpNCNfFNW0w-ENsQiIXhoYBMrlEGvmyPeIK_yark_c16oek/s1600/Screenshot+2020-04-24+at+11.22.18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="484" data-original-width="982" height="196" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw8HxgNEUya5b04bzkQODgA3MuvJfnSOV6R-Bw58ia1Nr73KpUhgT5HTRWnzcFFiZLYiHk_9qfI5Zh7oTAnL42pWl0voNulpNCNfFNW0w-ENsQiIXhoYBMrlEGvmyPeIK_yark_c16oek/s400/Screenshot+2020-04-24+at+11.22.18.png" width="400" /></a></div>
<br />
<h3>
Starting the Cluster
</h3>
We are nearly done with the preparations for the deployment. There is one last thing we need to do - start our local Kubernetes cluster. This is done by executing the following command:
<br />
<code><br />minikube start</code>
<br />
<br />
<h3>
The Deployment
</h3>
In order to deploy our database and application we will be using Skaffold. In the root of your project create a file called skaffold.yml with the following contents:
<br />
<br />
<br />
<pre class="xml" name="code">apiVersion: skaffold/v2alpha3
kind: Config
build:
artifacts:
- image: speedment-spring-app-example
docker:
dockerfile: Dockerfile
deploy:
kubectl:
manifests:
- k8s/app/*
- k8s/storage/*
</pre>
<br />
With this file completed, we are finally ready for deployment. From the project root, execute the following command:
<br />
<code><br />skaffold dev --port-forward=true</code>
<br />
<br />
When we execute this command, two things will happen:<br />
<br />
<ol>
<li>A Docker image will be created from the Dockerfile we created earlier
</li>
<li>Deployments and services will be created from the configurations we created earlier
</li>
</ol>
<br />
Once your microservice starts up, you can use it the same way you used it earlier. The only difference now is that it is running from a Kubernetes cluster.
<br />
<br />
<b>Note:</b> It takes around 30-60 seconds for the Sakila database to boot up completely. Since our application starts a lot quicker than the Sakila database, it will most likely crash and restart a couple of times before the database is ready.
<br />
<br />
<h3>
Summary
</h3>
Creating applications in a time-efficient manner can sometimes be hard. We have explained how to generate a microservice from a database and deploy it to a Kubernetes cluster, so hopefully, you’ve learned something that will reduce your development time.
<br />
<br />
We hope you’ve enjoyed reading this article as much as we enjoyed writing it. The final version of the source code from this article can be found <a href="https://github.com/dekmm/speedment-spring-app-example" target="_blank">here</a>.
<br />
<br />
<h3>
Authors</h3>
Per Minborg<br />
Mislav Miličević<br />
<br />
<h3>
Resources</h3>
<div>
The <a href="https://speedment.com/download/" target="_blank">Speedment Initializer</a> capable of generating project templates</div>
<div>
<a href="https://github.com/speedment/speedment" target="_blank">Speedment OpenSource </a>on GitHub<br />
Speedment <a href="https://speedment.github.io/speedment-doc/" target="_blank">Online Manual</a><br />
<a href="https://github.com/dekmm/speedment-spring-app-example" target="_blank">Github Repository</a> with the final version of the source code</div>
<div>
<a href="https://dev.mysql.com/doc/index-other.html" target="_blank">Sakila sample database</a> </div>
<div>
<br /></div>
<br />
<br /></div>
</div>
Per Minborghttp://www.blogger.com/profile/08526963148025854611noreply@blogger.com0Palo Alto, CA, USA37.4418834 -122.143019537.2400059 -122.46574299999999 37.643760900000004 -121.820296