mirror of
https://github.com/corda/corda.git
synced 2024-12-28 00:38:55 +00:00
423 lines
28 KiB
HTML
423 lines
28 KiB
HTML
<!-- If you edit this, then please make the same changes to layout_for_doc_website.html, as that is used for the web
|
|
doc site generation which we put analytics tracking on to identify any potential problem pages -->
|
|
|
|
|
|
|
|
|
|
<!DOCTYPE html>
|
|
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
|
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
|
<head>
|
|
<meta charset="utf-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<title>Load testing — R3 Corda latest documentation</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="top" title="R3 Corda latest documentation" href="index.html"/>
|
|
<link rel="next" title="What is a corda network?" href="setting-up-a-corda-network.html"/>
|
|
<link rel="prev" title="Interest rate swaps" href="contract-irs.html"/>
|
|
|
|
|
|
<script src="_static/js/modernizr.min.js"></script>
|
|
|
|
</head>
|
|
|
|
<body class="wy-body-for-nav" role="document">
|
|
|
|
<div class="wy-grid-for-nav">
|
|
|
|
|
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
|
<div class="wy-side-scroll">
|
|
<div class="wy-side-nav-search">
|
|
|
|
|
|
|
|
|
|
<a href="index.html" class="icon icon-home"> R3 Corda
|
|
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
|
|
<div class="version">
|
|
latest
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div role="search">
|
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
|
<input type="text" name="q" placeholder="Search docs" />
|
|
<input type="hidden" name="check_keywords" value="yes" />
|
|
<input type="hidden" name="area" value="default" />
|
|
</form>
|
|
</div>
|
|
|
|
|
|
<br>
|
|
<a href="api/index.html">API reference</a>
|
|
<br>
|
|
<a href="https://discourse.corda.net">Discourse Forums</a>
|
|
<br>
|
|
<a href="http://slack.corda.net">Slack</a>
|
|
<br>
|
|
|
|
</div>
|
|
|
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
|
|
|
|
|
|
|
<p class="caption"><span class="caption-text">Getting started</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="inthebox.html">What’s included?</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="getting-set-up.html">Getting set up</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="getting-set-up-fault-finding.html">Troubleshooting</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="running-the-demos.html">Running the demos</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="CLI-vs-IDE.html">CLI vs IDE</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Key concepts</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="transaction-data-types.html">Data types</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="merkle-trees.html">Transaction tear-offs</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="consensus.html">Consensus model</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="clauses.html">Clauses</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">CorDapps</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html">CorDapp basics</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-cordapp.html">The CorDapp template</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">The Corda node</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="clientrpc.html">Client RPC</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="persistence.html">Persistence</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="node-administration.html">Node administration</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="corda-configuration-file.html">Node configuration</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="corda-plugins.html">The Corda plugin framework</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="node-services.html">Brief introduction to the node services</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="node-explorer.html">Node Explorer</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="permissioning.html">Network permissioning</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Tutorials</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-contract.html">Writing a contract</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-contract-clauses.html">Writing a contract using clauses</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-test-dsl.html">Writing a contract test</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-integration-testing.html">Integration testing</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-clientrpc-api.html">Client RPC API tutorial</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-building-transactions.html">Building transactions</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="flow-state-machines.html">Writing flows</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="flow-testing.html">Writing flow tests</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="running-a-notary.html">Running a notary service</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="using-a-notary.html">Using a notary service</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="oracles.html">Writing oracle services</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial-attachments.html">Using attachments</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="event-scheduling.html">Event scheduling</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Other</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="network-simulator.html">Network Simulator</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Component library</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="contract-catalogue.html">Contract catalogue</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="contract-irs.html">Interest rate swaps</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Appendix</span></p>
|
|
<ul class="current">
|
|
<li class="toctree-l1 current"><a class="current reference internal" href="#">Load testing</a><ul>
|
|
<li class="toctree-l2"><a class="reference internal" href="#configuration-of-the-load-testing-cluster">Configuration of the load testing cluster</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#running-the-load-tests">Running the load tests</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#configuration-of-individual-load-tests">Configuration of individual load tests</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#how-to-write-a-load-test">How to write a load test</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="toctree-l1"><a class="reference internal" href="setting-up-a-corda-network.html">What is a corda network?</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="secure-coding-guidelines.html">Secure coding guidelines</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="release-process.html">Release process</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="release-notes.html">Release notes</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="codestyle.html">Code style guide</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="building-the-docs.html">Building the documentation</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="publishing-corda.html">Publishing Corda</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="azure-vm.html">Working with the Corda Demo on Azure Marketplace</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Glossary</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="glossary.html">Glossary</a></li>
|
|
</ul>
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
|
|
|
|
|
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
|
<a href="index.html">R3 Corda</a>
|
|
</nav>
|
|
|
|
|
|
|
|
<div class="wy-nav-content">
|
|
<div class="rst-content">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
|
<ul class="wy-breadcrumbs">
|
|
<li><a href="index.html">Docs</a> »</li>
|
|
|
|
<li>Load testing</li>
|
|
<li class="wy-breadcrumbs-aside">
|
|
|
|
|
|
<a href="_sources/loadtesting.txt" rel="nofollow"> View page source</a>
|
|
|
|
|
|
</li>
|
|
</ul>
|
|
<hr/>
|
|
</div>
|
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
|
<div itemprop="articleBody">
|
|
|
|
<div class="section" id="load-testing">
|
|
<h1>Load testing<a class="headerlink" href="#load-testing" title="Permalink to this headline">¶</a></h1>
|
|
<p>This section explains how to apply random load to nodes to stress test them. It also allows the specification of disruptions that strain different resources, allowing us to inspect the nodes’ behaviour under extreme conditions.</p>
|
|
<p>The load-testing framework is incomplete and is not part of CI currently, but the basic pieces are there.</p>
|
|
<div class="section" id="configuration-of-the-load-testing-cluster">
|
|
<h2>Configuration of the load testing cluster<a class="headerlink" href="#configuration-of-the-load-testing-cluster" title="Permalink to this headline">¶</a></h2>
|
|
<p>The load-testing framework currently assumes the following about the node cluster:</p>
|
|
<ul class="simple">
|
|
<li>The nodes are managed as a systemd service</li>
|
|
<li>The node directories are the same across the cluster</li>
|
|
<li>The messaging ports are the same across the cluster</li>
|
|
<li>The executing identity of the load-test has SSH access to all machines</li>
|
|
<li>There is a single network map service node</li>
|
|
<li>There is a single notary node</li>
|
|
<li>Some disruptions also assume other tools (like openssl) to be present</li>
|
|
</ul>
|
|
<p>Note that these points could and should be relaxed as needed.</p>
|
|
<p>The load test Main expects a single command line argument that points to a configuration file specifying the cluster hosts and optional overrides for the default configuration:</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span># nodeHosts = ["host1", "host2"]
|
|
# sshUser = "someusername", by default it uses the System property "user.name"
|
|
localCertificatesBaseDirectory = "build/load-test/certificates"
|
|
localTunnelStartingPort = 10000
|
|
remoteNodeDirectory = "/opt/r3cev"
|
|
remoteMessagingPort = 31337
|
|
remoteSystemdServiceName = "r3cev-node"
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="running-the-load-tests">
|
|
<h2>Running the load tests<a class="headerlink" href="#running-the-load-tests" title="Permalink to this headline">¶</a></h2>
|
|
<p>In order to run the loadtests you need to have an active SSH-agent running with a single identity added that has SSH access to the loadtest cluster.</p>
|
|
<p>You can use either IntelliJ or the gradle command line to start the tests.</p>
|
|
<p>To use gradle: <code class="docutils literal"><span class="pre">./gradlew</span> <span class="pre">tools:loadtest:run</span> <span class="pre">-Ploadtest-config=PATH_TO_LOADTEST_CONF</span></code></p>
|
|
<p>To use IntelliJ simply run Main.kt with the config path supplied as an argument.</p>
|
|
</div>
|
|
<div class="section" id="configuration-of-individual-load-tests">
|
|
<h2>Configuration of individual load tests<a class="headerlink" href="#configuration-of-individual-load-tests" title="Permalink to this headline">¶</a></h2>
|
|
<p>The load testing configurations are not set-in-stone and are meant to be played with to see how the nodes react.</p>
|
|
<p>There are a couple of top-level knobs to tweak test behaviour:</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="cm">/**</span>
|
|
<span class="cm"> * @param parallelism Number of concurrent threads to use to run commands. Note that the actual parallelism may be</span>
|
|
<span class="cm"> * further limited by the batches that [generate] returns.</span>
|
|
<span class="cm"> * @param generateCount Number of total commands to generate. Note that the actual number of generated commands may</span>
|
|
<span class="cm"> * exceed this, it is used just for cutoff.</span>
|
|
<span class="cm"> * @param clearDatabaseBeforeRun Indicates whether the node databases should be cleared before running the test. May</span>
|
|
<span class="cm"> * significantly slow down testing as this requires bringing the nodes down and up again.</span>
|
|
<span class="cm"> * @param gatherFrequency Indicates after how many commands we should gather the remote states.</span>
|
|
<span class="cm"> * @param disruptionPatterns A list of disruption-lists. The test will be run for each such list, and the test will</span>
|
|
<span class="cm"> * be interleaved with the specified disruptions.</span>
|
|
<span class="cm"> */</span>
|
|
<span class="k">data</span> <span class="k">class</span> <span class="nc">RunParameters</span><span class="p">(</span>
|
|
<span class="k">val</span> <span class="py">parallelism</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">generateCount</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">clearDatabaseBeforeRun</span><span class="p">:</span> <span class="n">Boolean</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">gatherFrequency</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">disruptionPatterns</span><span class="p">:</span> <span class="n">List</span><span class="p"><</span><span class="n">List</span><span class="p"><</span><span class="n">DisruptionSpec</span><span class="p">>></span>
|
|
<span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The one thing of note is <code class="docutils literal"><span class="pre">disruptionPatterns</span></code>, which may be used to specify ways of disrupting the normal running of the load tests.</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">data</span> <span class="k">class</span> <span class="nc">Disruption</span><span class="p">(</span>
|
|
<span class="k">val</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">disrupt</span><span class="p">:</span> <span class="p">(</span><span class="n">NodeHandle</span><span class="p">,</span> <span class="n">SplittableRandom</span><span class="p">)</span> <span class="p">-></span> <span class="n">Unit</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="k">data</span> <span class="k">class</span> <span class="nc">DisruptionSpec</span><span class="p">(</span>
|
|
<span class="k">val</span> <span class="py">nodeFilter</span><span class="p">:</span> <span class="p">(</span><span class="n">NodeHandle</span><span class="p">)</span> <span class="p">-></span> <span class="n">Boolean</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">disruption</span><span class="p">:</span> <span class="n">Disruption</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">noDisruptionWindowMs</span><span class="p">:</span> <span class="n">LongRange</span>
|
|
<span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Disruptions run concurrently in loops on randomly chosen nodes filtered by <code class="docutils literal"><span class="pre">nodeFilter</span></code> at somewhat random intervals.</p>
|
|
<p>As an example take <code class="docutils literal"><span class="pre">strainCpu</span></code> which overutilises the processor:</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">fun</span> <span class="nf">strainCpu</span><span class="p">(</span><span class="n">parallelism</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="n">durationSeconds</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="p">=</span> <span class="n">Disruption</span><span class="p">(</span><span class="s">"Put strain on cpu"</span><span class="p">)</span> <span class="p">{</span> <span class="n">node</span><span class="p">,</span> <span class="n">random</span> <span class="p">-></span>
|
|
<span class="k">val</span> <span class="py">shell</span> <span class="p">=</span> <span class="s">"for c in {1..$parallelism} ; do openssl enc -aes-128-cbc -in /dev/urandom -pass pass: -e > /dev/null & done && JOBS=\$(jobs -p) && (sleep $durationSeconds && kill \$JOBS) & wait"</span>
|
|
<span class="n">node</span><span class="p">.</span><span class="n">connection</span><span class="p">.</span><span class="n">runShellCommandGetOutput</span><span class="p">(</span><span class="n">shell</span><span class="p">).</span><span class="n">getResultOrThrow</span><span class="p">()</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>We can use this by specifying a <code class="docutils literal"><span class="pre">DisruptionSpec</span></code> in the load test’s <code class="docutils literal"><span class="pre">RunParameters</span></code>:</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="n">DisruptionSpec</span><span class="p">(</span>
|
|
<span class="n">disruption</span> <span class="p">=</span> <span class="n">strainCpu</span><span class="p">(</span><span class="n">parallelism</span> <span class="p">=</span> <span class="m">4</span><span class="p">,</span> <span class="n">durationSeconds</span> <span class="p">=</span> <span class="m">10</span><span class="p">),</span>
|
|
<span class="n">nodeFilter</span> <span class="p">=</span> <span class="p">{</span> <span class="k">true</span> <span class="p">},</span>
|
|
<span class="n">noDisruptionWindowMs</span> <span class="p">=</span> <span class="m">5000L</span><span class="p">..</span><span class="m">10000L</span>
|
|
<span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>This means every 5-10 seconds at least one randomly chosen nodes’ cores will be spinning 100% for 10 seconds.</p>
|
|
</div>
|
|
<div class="section" id="how-to-write-a-load-test">
|
|
<h2>How to write a load test<a class="headerlink" href="#how-to-write-a-load-test" title="Permalink to this headline">¶</a></h2>
|
|
<p>A load test is basically defined by a random datastructure generator that specifies a unit of work a node should perform, a function that performs this work, and a function that predicts what state the node should end up in by doing so:</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">data</span> <span class="k">class</span> <span class="nc">LoadTest</span><span class="p"><</span><span class="n">T</span><span class="p">,</span> <span class="n">S</span><span class="p">>(</span>
|
|
<span class="k">val</span> <span class="py">testName</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">generate</span><span class="p">:</span> <span class="n">Nodes</span><span class="p">.(</span><span class="n">S</span><span class="p">,</span> <span class="n">Int</span><span class="p">)</span> <span class="p">-></span> <span class="n">Generator</span><span class="p"><</span><span class="n">List</span><span class="p"><</span><span class="n">T</span><span class="p">>>,</span>
|
|
<span class="k">val</span> <span class="py">interpret</span><span class="p">:</span> <span class="p">(</span><span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">)</span> <span class="p">-></span> <span class="n">S</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">execute</span><span class="p">:</span> <span class="n">Nodes</span><span class="p">.(</span><span class="n">T</span><span class="p">)</span> <span class="p">-></span> <span class="n">Unit</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">gatherRemoteState</span><span class="p">:</span> <span class="n">Nodes</span><span class="p">.(</span><span class="n">S</span><span class="p">?)</span> <span class="p">-></span> <span class="n">S</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">isConsistent</span><span class="p">:</span> <span class="p">(</span><span class="n">S</span><span class="p">)</span> <span class="p">-></span> <span class="n">Boolean</span> <span class="p">=</span> <span class="p">{</span> <span class="k">true</span> <span class="p">}</span>
|
|
<span class="p">)</span> <span class="p">{</span>
|
|
</pre></div>
|
|
</div>
|
|
<p><code class="docutils literal"><span class="pre">LoadTest</span></code> is parameterised over <code class="docutils literal"><span class="pre">T</span></code>, the unit of work, and <code class="docutils literal"><span class="pre">S</span></code>, the state type that aims to track remote node states. As an example let’s look at the Self Issue test. This test simply creates Cash Issues from nodes to themselves, and then checks the vault to see if the numbers add up:</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">data</span> <span class="k">class</span> <span class="nc">SelfIssueCommand</span><span class="p">(</span>
|
|
<span class="k">val</span> <span class="py">command</span><span class="p">:</span> <span class="n">CashCommand</span><span class="p">.</span><span class="n">IssueCash</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">node</span><span class="p">:</span> <span class="n">NodeHandle</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="k">data</span> <span class="k">class</span> <span class="nc">SelfIssueState</span><span class="p">(</span>
|
|
<span class="k">val</span> <span class="py">vaultsSelfIssued</span><span class="p">:</span> <span class="n">Map</span><span class="p"><</span><span class="n">Party</span><span class="p">,</span> <span class="n">Long</span><span class="p">></span>
|
|
<span class="p">)</span> <span class="p">{</span>
|
|
<span class="k">fun</span> <span class="nf">copyVaults</span><span class="p">():</span> <span class="n">HashMap</span><span class="p"><</span><span class="n">Party</span><span class="p">,</span> <span class="n">Long</span><span class="p">></span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="n">HashMap</span><span class="p">(</span><span class="n">vaultsSelfIssued</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="k">val</span> <span class="py">selfIssueTest</span> <span class="p">=</span> <span class="n">LoadTest</span><span class="p"><</span><span class="n">SelfIssueCommand</span><span class="p">,</span> <span class="n">SelfIssueState</span><span class="p">>(</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The unit of work <code class="docutils literal"><span class="pre">SelfIssueCommand</span></code> simply holds an Issue and a handle to a node where the issue should be submitted. The <code class="docutils literal"><span class="pre">generate</span></code> method should provide a generator for these.</p>
|
|
<p>The state <code class="docutils literal"><span class="pre">SelfIssueState</span></code> then holds a map from node identities to a Long that describes the sum quantity of the generated issues (we fixed the currency to be USD).</p>
|
|
<p>The invariant we want to hold then simply is: The sum of submitted Issues should be the sum of the quantities in the vaults.</p>
|
|
<p>The <code class="docutils literal"><span class="pre">interpret</span></code> function should take a <code class="docutils literal"><span class="pre">SelfIssueCommand</span></code> and update <code class="docutils literal"><span class="pre">SelfIssueState</span></code> to reflect the change we’re expecting in the remote nodes. In our case this will simply be adding the issued amount to the corresponding node’s Long.</p>
|
|
<p>The <code class="docutils literal"><span class="pre">execute</span></code> function should perform the action on the cluster. In our case it will simply take the node handle and submit an RPC request for the Issue.</p>
|
|
<p>The <code class="docutils literal"><span class="pre">gatherRemoteState</span></code> function should check the actual remote nodes’ states and see whether they conflict with our local predictions (and should throw if they do). This function deserves its own paragraph.</p>
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="k">val</span> <span class="py">gatherRemoteState</span><span class="p">:</span> <span class="n">Nodes</span><span class="p">.(</span><span class="n">S</span><span class="p">?)</span> <span class="p">-></span> <span class="n">S</span><span class="p">,</span>
|
|
</pre></div>
|
|
</div>
|
|
<p><code class="docutils literal"><span class="pre">gatherRemoteState</span></code> gets as input handles to all the nodes, and the current predicted state, or null if this is the initial gathering.</p>
|
|
<p>The reason it gets the previous state boils down to allowing non-deterministic predictions about the nodes’ remote states. Say some piece of work triggers an asynchronous notification of a node. We need to account both for the case when the node hasn’t received the notification and for the case when it has. In these cases <code class="docutils literal"><span class="pre">S</span></code> should somehow represent a collection of possible states, and <code class="docutils literal"><span class="pre">gatherRemoteState</span></code> should “collapse” the collection based on the observations it makes. Of course we don’t need this for the simple case of the Self Issue test.</p>
|
|
<p>The last parameter <code class="docutils literal"><span class="pre">isConsistent</span></code> is used to poll for eventual consistency at the end of a load test. This is not needed for self-issuance.</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
<footer>
|
|
|
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
|
|
|
<a href="setting-up-a-corda-network.html" class="btn btn-neutral float-right" title="What is a corda network?" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
|
|
|
|
|
|
<a href="contract-irs.html" class="btn btn-neutral" title="Interest rate swaps" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
|
|
|
</div>
|
|
|
|
|
|
<hr/>
|
|
|
|
<div role="contentinfo">
|
|
<p>
|
|
© Copyright 2016, R3 Limited.
|
|
|
|
</p>
|
|
</div>
|
|
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
|
|
|
</footer>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
var DOCUMENTATION_OPTIONS = {
|
|
URL_ROOT:'./',
|
|
VERSION:'latest',
|
|
COLLAPSE_INDEX:false,
|
|
FILE_SUFFIX:'.html',
|
|
HAS_SOURCE: true
|
|
};
|
|
</script>
|
|
<script type="text/javascript" src="_static/jquery.js"></script>
|
|
<script type="text/javascript" src="_static/underscore.js"></script>
|
|
<script type="text/javascript" src="_static/doctools.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
jQuery(function () {
|
|
SphinxRtdTheme.StickyNav.enable();
|
|
});
|
|
</script>
|
|
|
|
|
|
</body>
|
|
</html> |