<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Simer Plaha</title>
    <description>The latest articles on DEV Community by Simer Plaha (@simerplaha).</description>
    <link>https://dev.to/simerplaha</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F71944%2F0bb9a41e-54d9-46bd-9718-fd7ae28deb7a.jpeg</url>
      <title>DEV Community: Simer Plaha</title>
      <link>https://dev.to/simerplaha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/simerplaha"/>
    <language>en</language>
    <item>
      <title>Decentralised systems - SwayDB</title>
      <dc:creator>Simer Plaha</dc:creator>
      <pubDate>Thu, 12 Nov 2020 17:13:55 +0000</pubDate>
      <link>https://dev.to/simerplaha/decentralised-systems-swaydb-2d3</link>
      <guid>https://dev.to/simerplaha/decentralised-systems-swaydb-2d3</guid>
      <description>&lt;p&gt;&lt;code&gt;TimeOrder&lt;/code&gt; in &lt;a href="https://swaydb.simer.au/"&gt;SwayDB&lt;/a&gt; can be used by decentralised systems for managing un-ordered writes and/or replication requests.  &lt;/p&gt;

&lt;p&gt;Before going into details I will briefly explain the two types of &lt;code&gt;Ordering&lt;/code&gt; in SwayDB.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://swaydb.simer.au/ordering-data/?language=scala"&gt;KeyOrder&lt;/a&gt; - Similar to any sorted collection type this simply orders data by key. Simple stuff!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TimeOrder&lt;/code&gt; - Orders the sequence in which updates occur on a &lt;strong&gt;single key&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How is Time used?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Time&lt;/code&gt; is always stored with &lt;strong&gt;each write&lt;/strong&gt; (even for range updates).&lt;/p&gt;

&lt;p&gt;In the following example we've inserted &lt;code&gt;key1&lt;/code&gt;  with value &lt;code&gt;1&lt;/code&gt; at time &lt;code&gt;0&lt;/code&gt;  and then updated the value by &lt;strong&gt;incrementing&lt;/strong&gt; it by &lt;code&gt;5&lt;/code&gt; first and then &lt;strong&gt;multiplying&lt;/strong&gt; it by &lt;code&gt;10&lt;/code&gt; which sets the final value to &lt;code&gt;(1 + 5) * 10 = 60&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we were to submit the same updates in reverse order the final value would still be the same (&lt;code&gt;60&lt;/code&gt;) since compaction applies these updates based on &lt;code&gt;time&lt;/code&gt; and not the actual request order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without time, the above updates would've resulted in different final value of &lt;code&gt;1 * 10 + 5 = 15&lt;/code&gt;  and not our intended &lt;code&gt;60&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can it be used by decentralised systems?
&lt;/h2&gt;

&lt;p&gt;I'm going to consider the use-case that writes can occur on any machine, at any time, for any key which may or may not be replicated to other machines. &lt;/p&gt;

&lt;p&gt;SwayDB's job is to ensure that writes by a decentralised system should eventually result in the same final value regardless of when a write or replication request was received by the machine. The only requirement is that each machine's SwayDB instance is initialised with the same &lt;code&gt;TimeOrder&lt;/code&gt; function (documented below). &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Time&lt;/code&gt; is just a serialisable type so it can be any &lt;code&gt;class&lt;/code&gt; with any number of fields. For our example we will use the following &lt;code&gt;CustomTime&lt;/code&gt; class with two fields&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;machineId&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;   
                      &lt;span class="n"&gt;machineLocalTime&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;machineId&lt;/code&gt; - unique ID assigned to each machine on boot that does not change even if the machine reboots.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;machineLocalTime&lt;/code&gt; - assigned to each write (put, update, remove, expire etc) initialised by each machine that creates the write request.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example write behaviour
&lt;/h3&gt;

&lt;p&gt;Suppose &lt;strong&gt;machine0&lt;/strong&gt; receives the following requests (in any order) that are replicated to &lt;strong&gt;machine1&lt;/strong&gt; (in any order).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;strong&gt;machine1&lt;/strong&gt; receives the following requests (in any order) that are also replicated to &lt;strong&gt;machine0&lt;/strong&gt; (in any order).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expectation&lt;/strong&gt; - We want the final value of &lt;code&gt;key1&lt;/code&gt; to be &lt;code&gt;(1 + 5 * 10 - 10) * 20 = 820&lt;/code&gt; on both machines regardless of the order in which the request were received.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom TimeOrder
&lt;/h3&gt;

&lt;p&gt;We can achieve the above expectation with just the following &lt;code&gt;TimeOrder&lt;/code&gt; function which orders writes by &lt;code&gt;machineId&lt;/code&gt; first and then &lt;code&gt;machineLocalTime&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;customTimeOrder&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;  
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TimeOrder&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CustomTime&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
      &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;machineId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;machineId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
        &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;machineLocalTime&lt;/span&gt; &lt;span class="n"&gt;compareTo&lt;/span&gt; &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;machineLocalTime&lt;/span&gt;  
      &lt;span class="k"&gt;else&lt;/span&gt;  
        &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;machineId&lt;/span&gt; &lt;span class="n"&gt;compareTo&lt;/span&gt; &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;machineId&lt;/span&gt;  
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  API Status
&lt;/h2&gt;

&lt;p&gt;Currently &lt;code&gt;TimeOrder&lt;/code&gt; API is private to SwayDB's &lt;code&gt;core&lt;/code&gt; and is enabled when functions are &lt;a href="https://swaydb.simer.au/api/pure-functions/?language=scala"&gt;turned on&lt;/a&gt;. It is used by all &lt;a href="https://swaydb.simer.au/implementation/level/?language=scala"&gt;Levels&lt;/a&gt; to execute non-blocking reads and it decouples reads from compaction i.e. if compaction is running on a &lt;a href="https://swaydb.simer.au/implementation/segment/?language=scala"&gt;Segment&lt;/a&gt; it does &lt;strong&gt;not&lt;/strong&gt; block or lock reads. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;TimeOrder&lt;/code&gt;'s public API is pending test-cases.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>scala</category>
      <category>java</category>
      <category>database</category>
    </item>
    <item>
      <title>MultiMap - Tables in SwayDB</title>
      <dc:creator>Simer Plaha</dc:creator>
      <pubDate>Thu, 30 Jul 2020 04:50:13 +0000</pubDate>
      <link>https://dev.to/simerplaha/tables-in-swaydb-4i4d</link>
      <guid>https://dev.to/simerplaha/tables-in-swaydb-4i4d</guid>
      <description>&lt;p&gt;&lt;code&gt;MultiMap&lt;/code&gt; is an extension of &lt;code&gt;Map&lt;/code&gt; data type which allows storing multiple &lt;code&gt;Map&lt;/code&gt;s within a single &lt;a href="https://github.com/simerplaha/SwayDB" rel="noopener noreferrer"&gt;SwayDB&lt;/a&gt; instance. It mimics SQL's &lt;code&gt;Table&lt;/code&gt; which can be used to seggregate data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MultiMap&lt;/code&gt; is just a thin layer that uses custom types and &lt;a href="https://swaydb.simer.au/ordering-data/?language=scala/" rel="noopener noreferrer"&gt;KeyOrdering&lt;/a&gt; to manage data segregation. &lt;/p&gt;

&lt;p&gt;The following code snippets demo few core functionality of &lt;code&gt;MultiMap&lt;/code&gt; like nesting, expiration, streaming, transactions, replace &amp;amp; remove. &lt;/p&gt;

&lt;h2&gt;
  
  
  Initialise &lt;code&gt;MultiMap&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;swaydb._&lt;/span&gt; &lt;span class="c1"&gt;//import SwayDB's API&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;swaydb.serializers.Default._&lt;/span&gt; &lt;span class="c1"&gt;//import default serialisers&lt;/span&gt;

&lt;span class="c1"&gt;//initialise an in-memory multiMap  &lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;map&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;MultiMap_EAP&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Long&lt;/span&gt;, &lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Bag.Less&lt;/span&gt;&lt;span class="o"&gt;]()&lt;/span&gt;

&lt;span class="c1"&gt;//or initialise an persistent multiMap &lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;pMap&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;persistent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;MultiMap_EAP&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Long&lt;/span&gt;, &lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Bag.Less&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="s"&gt;"myDir"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;String&lt;/code&gt; - The type of &lt;strong&gt;Map ID&lt;/strong&gt;. In SQL this would be &lt;strong&gt;Table Name&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Long&lt;/code&gt; - The type of &lt;strong&gt;Key&lt;/strong&gt; for key-values stored in this Map. In SQL this would be &lt;strong&gt;primary key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;String&lt;/code&gt; - The type of &lt;strong&gt;Value&lt;/strong&gt; for key-values stored in the Map. In SQL this would be the &lt;strong&gt;Table row&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Nothing&lt;/code&gt; - The function type. Using &lt;code&gt;Nothing&lt;/code&gt; disables functions. Instead of a query language, SwayDB allows complex data modifications by submitting pure JVM functions. In SQL these would be &lt;code&gt;CREATE&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt; &amp;amp; &lt;code&gt;UPDATE&lt;/code&gt; queries. You can read more about this &lt;a href="https://dev.to/simerplaha/functions-as-queries-swaydb-538n"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Bag.Less&lt;/code&gt; - The effect type for all API calls. We can use &lt;a href="https://github.com/typelevel/cats-effect" rel="noopener noreferrer"&gt;Cats&lt;/a&gt;, &lt;a href="https://github.com/monix/monix" rel="noopener noreferrer"&gt;Monix&lt;/a&gt;, &lt;a href="https://github.com/zio/zio" rel="noopener noreferrer"&gt;ZIO&lt;/a&gt;, &lt;code&gt;Try&lt;/code&gt;, &lt;code&gt;Future&lt;/code&gt; or any other custom effect type. Using &lt;code&gt;Bag.Less&lt;/code&gt; disables effect management and simply returns the result as output.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating Tables
&lt;/h2&gt;

&lt;p&gt;The following creates two tables under the root map.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;usersTable&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapKey&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Users Table"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;productsTable&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapKey&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Products Table"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//this create another child table under Users Table.&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;userTablesChild&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;usersTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapKey&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Users Table's child"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//read all tables keys of userTable&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;usersTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;keys&lt;/span&gt;
&lt;span class="c1"&gt;//read all child tables of userTable&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;tables&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;usersTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;stream&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Schema tree
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5cg2a92jklovaon23ue5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5cg2a92jklovaon23ue5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating tables with default expiration
&lt;/h2&gt;

&lt;p&gt;Similar to above we can also create Tables/Maps that expire.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;scala.concurrent.duration._&lt;/span&gt;  

&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapKey&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Users Table"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expireAfter&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.d&lt;/span&gt;&lt;span class="n"&gt;ays&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapKey&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Products Table"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expireAt&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.&lt;/span&gt;&lt;span class="nv"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromNow&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Removing and replacing tables
&lt;/h2&gt;

&lt;p&gt;Replace creates a new table clearing all existing data including all existing child tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;//replace&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapKey&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Users Table"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expireAfter&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.d&lt;/span&gt;&lt;span class="n"&gt;ays&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//or remove to delete the map/table&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapKey&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Users Table"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Transactions
&lt;/h2&gt;

&lt;p&gt;Modifications to multiple Tables can be performed as a single batch transaction. The following snippet creates and commits two transaction entries for two different tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;//prepare statement for userTable and productTable  &lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;  
  &lt;span class="nv"&gt;usersTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toTransaction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Prepare&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"user1"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;  
    &lt;span class="nv"&gt;productsTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toTransaction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Prepare&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"product1"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  

&lt;span class="c1"&gt;//commit to root map  &lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  

&lt;span class="nv"&gt;usersTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
&lt;span class="nv"&gt;productsTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"product1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://swaydb.simer.au/api/write/transaction/?language=scala/" rel="noopener noreferrer"&gt;transaction&lt;/a&gt; for a list of all &lt;code&gt;Prepare&lt;/code&gt; statements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;See &lt;a href="https://github.com/simerplaha/SwayDB.scala.examples/blob/master/src/test/scala/multimapExample/MultiMap_Example.scala" rel="noopener noreferrer"&gt;MultiMap_Example.scala&lt;/a&gt; on Github which uses custom types with &lt;code&gt;circe&lt;/code&gt; for serialisation. &lt;/p&gt;

&lt;p&gt;Please consider staring the &lt;a href="https://github.com/simerplaha/SwayDB" rel="noopener noreferrer"&gt;SwayDB&lt;/a&gt; project if you find it useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  EAP
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;MultiMap&lt;/code&gt; is currently in preview version (EAP). See performance improvement task &lt;a href="https://github.com/simerplaha/SwayDB/issues/235" rel="noopener noreferrer"&gt;#235&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub repos
&lt;/h2&gt;

&lt;p&gt;Check out related GitHub repos&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB" rel="noopener noreferrer"&gt;SwayDB&lt;/a&gt; on GitHub.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.scala.examples" rel="noopener noreferrer"&gt;Scala&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.java.examples" rel="noopener noreferrer"&gt;Java&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.kotlin.examples" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://swaydb.simer.au/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>scala</category>
      <category>java</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Functions as Queries @ SwayDB</title>
      <dc:creator>Simer Plaha</dc:creator>
      <pubDate>Sun, 29 Mar 2020 16:43:52 +0000</pubDate>
      <link>https://dev.to/simerplaha/functions-as-queries-swaydb-538n</link>
      <guid>https://dev.to/simerplaha/functions-as-queries-swaydb-538n</guid>
      <description>&lt;p&gt;&lt;strong&gt;Conditional updates &amp;amp; deletes&lt;/strong&gt; are performed by submitting any &lt;strong&gt;Java&lt;/strong&gt;,  &lt;strong&gt;Scala&lt;/strong&gt;,  &lt;strong&gt;Kotlin&lt;/strong&gt;  or any native  &lt;strong&gt;JVM  code/function&lt;/strong&gt;. There is &lt;strong&gt;no query language&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Being just JVM functions/code we can&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be more &lt;strong&gt;expressive&lt;/strong&gt; in writing our query logic as we are not restricted by rules of a query language.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;external Java libraries&lt;/strong&gt; within our queries like Joda-Time for time management, Jackson or Circe for JSON parsing etc.&lt;/li&gt;
&lt;li&gt;Write &lt;strong&gt;test-cases&lt;/strong&gt; using familiar testing libraries like JUnit, kotlin.test, ScalaTest etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type-safe&lt;/strong&gt; - catch errors during compile time.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt; - No runtime parsing &amp;amp; compiling performance cost. See these &lt;a href="https://swaydb.simer.au/benchmarks/rocksdb/?language=scala/"&gt;benchmarks&lt;/a&gt; that show &lt;strong&gt;482,000+ writes per second&lt;/strong&gt;. Function updates follow the same write path as any basic write and do not incur any extra cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;A simple example which creates a &lt;code&gt;Map&amp;lt;String, Double&amp;gt;&lt;/code&gt; that stores &lt;strong&gt;productName&lt;/strong&gt; as key and &lt;strong&gt;price&lt;/strong&gt; as value. You can use custom classes (&lt;code&gt;Product.java&lt;/code&gt; for values) here but for simplicity &lt;code&gt;String&lt;/code&gt; and &lt;code&gt;Double&lt;/code&gt; is used.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update logic&lt;/strong&gt;: If a product has less than 2 days left to expiration, give a generous 50% discount!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Our function that implements the update logic. &lt;/span&gt;
&lt;span class="c1"&gt;//You can also use PureFunction.OnValue or PureFunction.OnKey.&lt;/span&gt;
&lt;span class="nc"&gt;PureFunction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OnKeyValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Return&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Deadline&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//if there are less than 2 days to expiry then apply discount.  &lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPresent&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;timeLeft&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;minusDays&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;isNegative&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
      &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;discountedPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.50&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//50% discount.&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discountedPrice&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//If the price is below $10&lt;/span&gt;
        &lt;span class="c1"&gt;//return Return.expire(Duration.ZERO); //expire it&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Return&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//or remove the product&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Return&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discountedPrice&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//else update with the discounted price&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;  
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Return&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nothing&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//else do nothing.&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;};&lt;/span&gt;  

&lt;span class="c1"&gt;//create our map with functions enabled.    &lt;/span&gt;
&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PureFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Return&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
  &lt;span class="nc"&gt;MapConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;functionsOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringSerializer&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;doubleSerializer&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerFunction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//register the discount function&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  

&lt;span class="c1"&gt;//insert two products that expire after a day. &lt;/span&gt;
&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MacBook Pro"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2799.00&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofDays&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;  
&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tesla"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;69275.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofDays&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;  

&lt;span class="c1"&gt;//apply the discount function.&lt;/span&gt;
&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;applyFunction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MacBook Pro"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Tesla"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can print the content of the Map with the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before the discount is applied will print&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;KeyVal(MacBook Pro, 2799.0)&lt;br&gt;
KeyVal(Tesla, 69275.0)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the discount is applied prints&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;KeyVal(MacBook Pro, 1399.5)&lt;br&gt;
KeyVal(Tesla, 34637.5)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See the above example on GitHub - &lt;a href="https://github.com/simerplaha/SwayDB.java.examples/blob/master/src/main/java/functions/DiscountApp.java"&gt;DiscountApp.java&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is function ID?
&lt;/h2&gt;

&lt;p&gt;Each &lt;code&gt;PureFunction&lt;/code&gt; type also implement a &lt;code&gt;String id&lt;/code&gt; value which gets stored in the database. Currently the &lt;code&gt;id&lt;/code&gt; is defaulted to &lt;code&gt;this.getClass().getName();&lt;/code&gt; which can be overridden by your function.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Note &amp;amp; TODOs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The function itself is not serialised. Only the function's &lt;code&gt;id&lt;/code&gt; gets serialised and stored in the database. TODO - Serialisable functions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.mightContainFunction&lt;/code&gt; can be used to check if a function is in use. TODO - Automatic function removal.&lt;/li&gt;
&lt;li&gt;TODO - stronger types when &lt;code&gt;registering&lt;/code&gt; and &lt;code&gt;applying&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB"&gt;SwayDB&lt;/a&gt;  on GitHub.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.java.examples"&gt;Java&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.kotlin.examples"&gt;Kotlin&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.scala.examples"&gt;Scala&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://swaydb.simer.au/"&gt;Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>scala</category>
      <category>storage</category>
    </item>
    <item>
      <title>Caching &amp; IOStrategy @ SwayDB</title>
      <dc:creator>Simer Plaha</dc:creator>
      <pubDate>Fri, 27 Mar 2020 04:30:41 +0000</pubDate>
      <link>https://dev.to/simerplaha/caching-iostrategy-swaydb-2a8e</link>
      <guid>https://dev.to/simerplaha/caching-iostrategy-swaydb-2a8e</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;We all know that Memory IO is 50-200 times faster than Disk IO!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt; plays a decent role in boosting &lt;strong&gt;read&lt;/strong&gt; and &lt;strong&gt;compaction&lt;/strong&gt; performance but some machines &amp;amp; smaller devices (eg: mobile phones) might have not have enough memory for cache so a &lt;strong&gt;configurable cache&lt;/strong&gt; allowing &lt;strong&gt;disabled&lt;/strong&gt;, &lt;strong&gt;partial&lt;/strong&gt; or &lt;strong&gt;full&lt;/strong&gt; cache is required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; - A &lt;code&gt;Segment(.seg)&lt;/code&gt; file in SwayDB is simply a byte array that stores other bytes arrays like keys, values, indexes etc (&lt;code&gt;Array&amp;lt;Array&amp;lt;Byte&amp;gt;&amp;gt;&lt;/code&gt;). All these bytes can be cached based on &lt;strong&gt;any condition&lt;/strong&gt; which is configurable. &lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring IO and Cache
&lt;/h2&gt;

&lt;p&gt;When accessing &lt;strong&gt;any file&lt;/strong&gt; with a custom format we generally &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the file (&lt;code&gt;OpenResource&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Read the file header or info (&lt;code&gt;ReadDataOverview&lt;/code&gt;) to understand the files content eg: format etc. &lt;/li&gt;
&lt;li&gt;Finally read the content of the file (&lt;code&gt;Compressed&lt;/code&gt; or &lt;code&gt;Uncompressed&lt;/code&gt; data). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following sample &lt;code&gt;ioStrategy&lt;/code&gt; function does exactly that where we get an &lt;code&gt;IOAction&lt;/code&gt; that describes what IO is being performed by SwayDB and in our function we define how we want to perform IO (&lt;code&gt;IOStrategy&lt;/code&gt;) for that action and &lt;strong&gt;also configure caching&lt;/strong&gt; for the read data/bytes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ioStrategy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IOAction&lt;/span&gt; &lt;span class="n"&gt;ioAction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isOpenResource&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
      &lt;span class="c1"&gt;//Here we are just opening the file so do synchronised IO because&lt;/span&gt;
      &lt;span class="c1"&gt;//blocking when opening a file might be cheaper than thread &lt;/span&gt;
      &lt;span class="c1"&gt;//context switching. Also set cacheOnAccess to true so that other &lt;/span&gt;
      &lt;span class="c1"&gt;//concurrent threads accessing the same file channel do not &lt;/span&gt;
      &lt;span class="c1"&gt;//open multiple channels to the same file.&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SynchronisedIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isReadDataOverview&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
      &lt;span class="c1"&gt;//Data overview is always small and less than 128 bytes and can be &lt;/span&gt;
      &lt;span class="c1"&gt;//read sychronously to avoid switching threads. Also cache&lt;/span&gt;
      &lt;span class="c1"&gt;//this data (cacheOnAccess) for the benifit of other threads and to save IO.&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SynchronisedIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
      &lt;span class="c1"&gt;//Here we are reading actual content of the file which can be compressed&lt;/span&gt;
      &lt;span class="c1"&gt;//or uncompressed. &lt;/span&gt;
      &lt;span class="nc"&gt;IOAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DataAction&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IOAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DataAction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ioAction&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isCompressed&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//If the data is compressed we do not want multiple threads to concurrently&lt;/span&gt;
        &lt;span class="c1"&gt;//decompress it so perform either Async or Sync IO for decompression&lt;/span&gt;
        &lt;span class="c1"&gt;//and then cache the compressed data. You can also read the compressed &lt;/span&gt;
        &lt;span class="c1"&gt;//and decompressed size with the following code&lt;/span&gt;
        &lt;span class="c1"&gt;//IOAction.ReadCompressedData dataAction = (IOAction.ReadCompressedData) action;  &lt;/span&gt;
        &lt;span class="c1"&gt;//dataAction.compressedSize();  &lt;/span&gt;
        &lt;span class="c1"&gt;//dataAction.decompressedSize();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AsyncIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
      &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
        &lt;span class="c1"&gt;//Else the data is not compressed so we allow concurrent access to it. &lt;/span&gt;
        &lt;span class="c1"&gt;//Here cacheOnAccess can also be set to true but that could allow multiple&lt;/span&gt;
        &lt;span class="c1"&gt;//threads to concurrently cache the same data. If cacheOnAccess is required &lt;/span&gt;
        &lt;span class="c1"&gt;//then use Asyc or Sync IO instead.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ConcurrentIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
      &lt;span class="o"&gt;}&lt;/span&gt;  
    &lt;span class="o"&gt;}&lt;/span&gt;  
  &lt;span class="o"&gt;}&lt;/span&gt;  
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will find the above &lt;code&gt;ioStrategy&lt;/code&gt; property in &lt;strong&gt;all data-blocks&lt;/strong&gt; that form a Segment - &lt;a href="https://swaydb.simer.au/configurations/sortedKeyIndex/?language=java/"&gt;SortedKeyIndex&lt;/a&gt;, &lt;a href="https://swaydb.simer.au/configurations/randomKeyIndex/?language=java/"&gt;RandomKeyIndex&lt;/a&gt;, &lt;a href="https://swaydb.simer.au/configurations/binarySearchIndex/?language=java/"&gt;BinarySearchIndex&lt;/a&gt;, &lt;a href="https://swaydb.simer.au/configurations/mightContainKeyIndex/?language=java/"&gt;MightContainIndex&lt;/a&gt; &amp;amp; &lt;a href="https://swaydb.simer.au/configurations/valuesConfig/?language=java/"&gt;ValuesConfig&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A Segment itself is also a &lt;strong&gt;data-block&lt;/strong&gt; and it's &lt;code&gt;ioStrategy&lt;/code&gt; can also be configured via &lt;a href="https://swaydb.simer.au/configurations/segmentConfig/?language=java/"&gt;SegmentConfig&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache control/limit with MemoryCache
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Caching should be controlled so that it does not lead to memory overflow!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;strong&gt;enable&lt;/strong&gt; or &lt;strong&gt;disable&lt;/strong&gt; caching for any or all of the following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bytes within a Segment  (&lt;code&gt;ByteCacheOnly&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Parsed key-values (&lt;code&gt;KeyValueCacheOnly&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Or all the above (&lt;code&gt;MemoryCache.All&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default &lt;code&gt;ByteCacheOnly&lt;/code&gt; is used because &lt;code&gt;KeyValueCacheOnly&lt;/code&gt; uses an in-memory &lt;code&gt;SkipList&lt;/code&gt; and inserts to a large &lt;code&gt;SkipList&lt;/code&gt; are expensive which is not useful for general use-case.  But &lt;code&gt;KeyValueCacheOnly&lt;/code&gt;  can be useful for applications that perform multiple reads to the same data and if that data rarely changes. &lt;/p&gt;

&lt;p&gt;An &lt;code&gt;Actor&lt;/code&gt; configuration is also required here which manages the cache in the background. You can configure the Actor to be a &lt;code&gt;Basic&lt;/code&gt;, &lt;code&gt;Timer&lt;/code&gt; or &lt;code&gt;TimerLoop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The following demoes how to configured all caches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Byte cache only&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMemoryCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
  &lt;span class="nc"&gt;MemoryCache&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;byteCacheOnlyBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minIOSeekSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;skipBlockCacheSeekSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StorageUnits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cacheCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StorageUnits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gb&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;actorConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActorConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Basic&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;ExecutionContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;DefaultConfigs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sweeperEC&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;  
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//or key-value cache only&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMemoryCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
  &lt;span class="nc"&gt;MemoryCache&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keyValueCacheOnlyBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cacheCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StorageUnits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gb&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxCachedKeyValueCountPerSegment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;actorConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActorConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Basic&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;ExecutionContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;DefaultConfigs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sweeperEC&lt;/span&gt;&lt;span class="o"&gt;())))&lt;/span&gt;  
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//or enable both the above.&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMemoryCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
  &lt;span class="nc"&gt;MemoryCache&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minIOSeekSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;skipBlockCacheSeekSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StorageUnits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cacheCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StorageUnits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gb&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxCachedKeyValueCountPerSegment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sweepCachedKeyValues&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;actorConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActorConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Basic&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;ExecutionContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;DefaultConfigs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sweeperEC&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;  
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;minIOSeekSize&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="[https://en.wikipedia.org/wiki/Block_(data_storage)](https://en.wikipedia.org/wiki/Block_(data_storage))"&gt;blockSize&lt;/a&gt; which set the minimum number of bytes to read for each IO. For example in the above configuration if you ask for &lt;code&gt;6000 bytes&lt;/code&gt; then &lt;code&gt;4096 * 2 bytes&lt;/code&gt; will be read. &lt;/p&gt;

&lt;p&gt;The value to set depends on your machines block size. On Mac this can be read with the following &lt;a href="[https://apple.stackexchange.com/questions/78802/what-are-the-sector-sizes-on-mac-os-x](https://apple.stackexchange.com/questions/78802/what-are-the-sector-sizes-on-mac-os-x)"&gt;command&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diskutil info / | grep "Block Size"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returns&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Device Block Size: 4096 Bytes&lt;br&gt;
Allocation Block Size: 4096 Bytes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;skipBlockCacheSeekSize&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This skips the &lt;code&gt;BlockCache&lt;/code&gt; and perform direct IO if the data size is greater than this value. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;cacheCapacity&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sets the total memory capacity. On overflow the oldest data in the cache is dropped by the &lt;code&gt;Actor&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;maxCachedKeyValueCountPerSegment&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If set, each &lt;code&gt;Segment&lt;/code&gt; is initialised with a dedicated &lt;code&gt;LimitSkipList&lt;/code&gt;. This cache is managed by the &lt;code&gt;Actor&lt;/code&gt; or by the &lt;code&gt;Segment&lt;/code&gt; itself if it gets deleted or when the max limit is reached.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;sweepCachedKeyValues&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Enables clearing cached key-values via the &lt;code&gt;Actor&lt;/code&gt;. If &lt;code&gt;false&lt;/code&gt;, key-values are kept in-memory indefinitely unless the &lt;code&gt;Segment&lt;/code&gt; gets deleted. This configuration can be used for smaller databases (eg: application configs) that read the same data more often. &lt;/p&gt;

&lt;h2&gt;
  
  
  Memory-mapping (MMAP)
&lt;/h2&gt;

&lt;p&gt;MMAP can also be optionally enabled for all files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
  &lt;span class="nc"&gt;MapConfig&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;functionsOff&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myMap"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;intSerializer&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;stringSerializer&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMmapAppendix&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//enable MMAP for appendix files&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMmapMaps&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;//enable MMAP for LevelZero write-ahead log files&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSegmentConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  &lt;span class="c1"&gt;//configuring MMAP for Segment files&lt;/span&gt;
      &lt;span class="nc"&gt;SegmentConfig&lt;/span&gt;  
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
         &lt;span class="o"&gt;...&lt;/span&gt;
         &lt;span class="c1"&gt;//either disable memory-mapping Segments&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mmap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MMAP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; 
         &lt;span class="c1"&gt;//or enable for writes and reads.&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mmap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MMAP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeAndRead&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
         &lt;span class="c1"&gt;//or enable for reads only. &lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mmap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MMAP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
        &lt;span class="o"&gt;...&lt;/span&gt;
     &lt;span class="o"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  

&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Optional[one]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;You are in full control of &lt;strong&gt;Caching&lt;/strong&gt; &amp;amp; &lt;strong&gt;IO&lt;/strong&gt; and can configure it to suit your application needs. If your &lt;code&gt;IOStrategy&lt;/code&gt; configurations uses only &lt;code&gt;AsyncIO&lt;/code&gt; and &lt;code&gt;ConcurrentIO&lt;/code&gt; then you can truely build &lt;strong&gt;reactive applications&lt;/strong&gt; which are non-blocking end-to-end other than the file system IO performed by &lt;code&gt;java.nio.*&lt;/code&gt; classes. Support for &lt;a href="https://pagure.io/libaio"&gt;Libio&lt;/a&gt; to provide aysnc file system IO can be implemented as a feature if requested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB"&gt;SwayDB&lt;/a&gt;  on GitHub.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.java.examples"&gt;Java&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.kotlin.examples"&gt;Kotlin&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.scala.examples"&gt;Scala&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://swaydb.simer.au/"&gt;Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>scala</category>
      <category>kotlin</category>
      <category>storage</category>
    </item>
    <item>
      <title>Compression @ SwayDB</title>
      <dc:creator>Simer Plaha</dc:creator>
      <pubDate>Wed, 25 Mar 2020 12:13:44 +0000</pubDate>
      <link>https://dev.to/simerplaha/compression-swaydb-3p3o</link>
      <guid>https://dev.to/simerplaha/compression-swaydb-3p3o</guid>
      <description>&lt;p&gt;&lt;strong&gt;Enabling full compression can reduce data size by 89.3%!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4sKAzotY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/dqg8jwbzwny2htdph95l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4sKAzotY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/dqg8jwbzwny2htdph95l.png" alt="Alt Text" width="494" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compression is &lt;strong&gt;important&lt;/strong&gt; for performance because more data can be stored &amp;amp; read into memory within a &lt;a href="https://en.wikipedia.org/wiki/Block_(data_storage)"&gt;block&lt;/a&gt;, it reduces IOps and the cost of hosting data on servers/cloud. But &lt;strong&gt;over-compression&lt;/strong&gt; can get expensive due to time required for decompression which could effect read performance but it can also be useful for applications that need &lt;strong&gt;cold storage&lt;/strong&gt; or just &lt;strong&gt;high compression&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;configurable compression strategy&lt;/strong&gt; is required to support &lt;strong&gt;unique storage requirements&lt;/strong&gt; allowing us to define &lt;strong&gt;how much&lt;/strong&gt; &amp;amp; &lt;strong&gt;how often&lt;/strong&gt; we want to compress data. For example: if your data file (Segment) is of size 100MB with 100K key-values you can express your compression requirements like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Compress the full 100MB data file.&lt;/li&gt;
&lt;li&gt;  Compress data every 4MB.&lt;/li&gt;
&lt;li&gt;  Compress data every 1000 key-values.&lt;/li&gt;
&lt;li&gt;  Compress all data but reset compression every 10&lt;sup&gt;th&lt;/sup&gt;  key-value&lt;/li&gt;
&lt;li&gt;  Do not compress all data but compress every 10&lt;sup&gt;th&lt;/sup&gt;  key-value.&lt;/li&gt;
&lt;li&gt;  Compress  &lt;code&gt;binary-search-indexes&lt;/code&gt;  &amp;amp;  &lt;code&gt;hash-indexes&lt;/code&gt;  but not other data-blocks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;strong&gt;data-block&lt;/strong&gt; is referred to a logical set of bytes (&lt;code&gt;Array&amp;lt;Byte&amp;gt;&lt;/code&gt;) that are stored within a Segment like indexes, keys, values etc. A Segment itself is a data-block that stores other data-blocks within itself (&lt;code&gt;Array&amp;lt;Array&amp;lt;Byte&amp;gt;&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Compression strategies
&lt;/h2&gt;

&lt;p&gt;You can combine, enable or disable any or all of the following compression strategies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Internal-compression includes &lt;strong&gt;prefix compression&lt;/strong&gt; and &lt;strong&gt;duplicate value elimination&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  External-compression uses &lt;strong&gt;LZ4&lt;/strong&gt; and/or &lt;strong&gt;Snappy&lt;/strong&gt; which can applied selectively to parts of a file or to the entire file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prefix compression
&lt;/h2&gt;

&lt;p&gt;Prefix compression stores all keys in a compressed group format in their sorted order. Reading a single key from that group requires decompressing all keys that exist before the searched key within the group, so for &lt;strong&gt;read performance&lt;/strong&gt; it is useful to leave some keys uncompressed. You can also prefix compress all keys if you just want &lt;strong&gt;high compression&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The following  &lt;code&gt;Map&lt;/code&gt;  is configured to compress &lt;strong&gt;4&lt;/strong&gt; keys into a group and starts a new group every &lt;strong&gt;5&lt;sup&gt;th&lt;/sup&gt;&lt;/strong&gt; key. The input  &lt;code&gt;boolean&lt;/code&gt;  parameter named  &lt;code&gt;keysOnly&lt;/code&gt;  is set to  &lt;code&gt;true&lt;/code&gt;  which applies prefix-compression to keys only, if  &lt;code&gt;false&lt;/code&gt;, it applies prefix-compression to keys and all &lt;strong&gt;metadata&lt;/strong&gt; that gets written with that key which would result in higher compression.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
  &lt;span class="nc"&gt;MapConfig&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;functionsOff&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myMap"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;intSerializer&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;stringSerializer&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSortedKeyIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
      &lt;span class="nc"&gt;SortedKeyIndex&lt;/span&gt;  
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prefixCompression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrefixCompression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Enable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PrefixCompression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resetCompressionAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;  
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  

&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Optional[one]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the following configuration prefix compression is applied to every &lt;strong&gt;5&lt;sup&gt;th&lt;/sup&gt;&lt;/strong&gt; key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prefixCompression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrefixCompression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Enable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PrefixCompression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compressAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefix compression can also be &lt;strong&gt;disabled&lt;/strong&gt; which optionally allows optimising sorted-index for direct binary-search without creating a dedicated binary-search byte array. You can read more about  &lt;code&gt;normaliseIndexForBinarySearch&lt;/code&gt;  &lt;a href="https://swaydb.simer.au/configurations/sortedKeyIndex/?language=java/"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prefixCompression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrefixCompression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Disable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Duplicate value elimination
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time-series&lt;/strong&gt; or &lt;strong&gt;events data&lt;/strong&gt; like weather, electricity, solar etc often contains duplicate values. Such duplicate values can be &lt;strong&gt;detected and eliminated&lt;/strong&gt; with the following configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ValuesConfig&lt;/span&gt;  
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compressDuplicateValues&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compressDuplicateRangeValues&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Duplicate value elimination is very &lt;strong&gt;cost effective&lt;/strong&gt; because it does not create or leave decompression markers on compressed data, instead all decompression information for that key is embedded within an already existing 1-2 bytes space.&lt;/p&gt;

&lt;p&gt;Range values created by the range APIs like  &lt;a href="https://swaydb.simer.au/api/write/remove-range/?language=java/"&gt;remove-range&lt;/a&gt;,  &lt;a href="https://swaydb.simer.au/api/write/update-range/?language=java/"&gt;update-range&lt;/a&gt;  &amp;amp;  &lt;a href="https://swaydb.simer.au/api/write/expire-range/?language=java/"&gt;expire-range&lt;/a&gt;  are most likely to have duplicate values and can be eliminated/compressed with the  &lt;code&gt;compressDuplicateRangeValues(true)&lt;/code&gt;  config.&lt;/p&gt;

&lt;h2&gt;
  
  
  External compression
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Every data-block written into Segment file is compressible! A Segment file is nothing special but just another data-block that stores other data-blocks within itself&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You will find a  &lt;code&gt;compression&lt;/code&gt;  property that configures external compression in &lt;strong&gt;all data-blocks&lt;/strong&gt; that form a Segment - &lt;a href="https://swaydb.simer.au/configurations/sortedKeyIndex/?language=java/"&gt;SortedKeyIndex&lt;/a&gt;,  &lt;a href="https://swaydb.simer.au/configurations/randomKeyIndex/?language=java/"&gt;RandomKeyIndex&lt;/a&gt;,  &lt;a href="https://swaydb.simer.au/configurations/binarySearchIndex/?language=java/"&gt;BinarySearchIndex&lt;/a&gt;,  &lt;a href="https://swaydb.simer.au/configurations/mightContainKeyIndex/?language=java/"&gt;MightContainIndex&lt;/a&gt;,  &lt;a href="https://swaydb.simer.au/configurations/valuesConfig/?language=java/"&gt;ValuesConfig&lt;/a&gt;  &amp;amp;  &lt;a href="https://swaydb.simer.au/configurations/segmentConfig/?language=java/"&gt;SegmentConfig&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All &lt;strong&gt;LZ4&lt;/strong&gt; instances and &lt;strong&gt;Snappy&lt;/strong&gt; are both supported.&lt;/p&gt;

&lt;p&gt;The following snippet demos how to apply compression to a &lt;a href="https://swaydb.simer.au/configurations/sortedKeyIndex/?language=java/"&gt;SortedKeyIndex/Linear-search-index&lt;/a&gt;. It tries to compress with LZ4 first at minimum 20.0% compression savings, if the compression was lower than 20.0% then Snappy is tried with the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SortedKeyIndex&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compressions&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;UncompressedBlockInfo&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="c1"&gt;//try running LZ4 with minimum 20.0% compression  &lt;/span&gt;
      &lt;span class="nc"&gt;Compression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lz4Pair&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LZ4Instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fastestJavaInstance&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LZ4Compressor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Fast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LZ4Instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fastestJavaInstance&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;LZ4Decompressor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fastDecompressor&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="c1"&gt;//if not try Snappy  &lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Compression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Snappy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;UncompressedBlockInfo&lt;/code&gt;  provides the data size (&lt;code&gt;info.uncompressedSize()&lt;/code&gt;) of the data-block being compressed which can optionally be used to determine if it should be compressed or not. For example: if the data size is already too small then you can disable compression by returning  &lt;code&gt;Collections.emptyList()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UncompressedBlockInfo&lt;/span&gt; &lt;span class="n"&gt;blockInfo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uncompressedSize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nc"&gt;StorageUnits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emptyList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//else do compression&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;compression&lt;/span&gt;&lt;span class="o"&gt;};&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to apply compression at a file Level?&lt;/strong&gt; Similar to above you can apply file level compression with  &lt;code&gt;SegmentConfig&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSegmentConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
  &lt;span class="nc"&gt;SegmentConfig&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
    &lt;span class="o"&gt;...&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compression&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;UncompressedBlockInfo&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;compression&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;  
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to limit compression by size &amp;amp; key-value count?
&lt;/h2&gt;

&lt;p&gt;The property &lt;code&gt;minSegmentSize&lt;/code&gt; sets the &lt;strong&gt;compressible size&lt;/strong&gt; of Segment and if the above &lt;code&gt;compression&lt;/code&gt; property is defined for a data-block then that data gets compressed every &lt;code&gt;minSegmentSize&lt;/code&gt; data block.&lt;/p&gt;

&lt;p&gt;The property &lt;code&gt;maxKeyValuesPerSegment&lt;/code&gt; also controls the compressible limit of a Segment which, along with &lt;code&gt;minSegmentSize&lt;/code&gt; enables checks to limit the maximum &lt;strong&gt;count/number&lt;/strong&gt; of key-values to store within a compressible Segment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSegmentConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
  &lt;span class="nc"&gt;SegmentConfig&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minSegmentSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StorageUnits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxKeyValuesPerSegment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;SwayDB's compression is highly configurable and can be tuned for unique storage requirements with different tradeoffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub repos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/simerplaha/SwayDB"&gt;SwayDB&lt;/a&gt; on GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/simerplaha/SwayDB.java.examples"&gt;Java&lt;/a&gt; examples repo.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/simerplaha/SwayDB.kotlin.examples"&gt;Kotlin&lt;/a&gt; examples repo.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/simerplaha/SwayDB.scala.examples"&gt;Scala&lt;/a&gt; examples repo.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://swaydb.simer.au/"&gt;Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>scala</category>
      <category>storage</category>
    </item>
    <item>
      <title>Hash-Index @ SwayDB</title>
      <dc:creator>Simer Plaha</dc:creator>
      <pubDate>Sun, 22 Mar 2020 06:01:48 +0000</pubDate>
      <link>https://dev.to/simerplaha/hash-index-swaydb-4k8</link>
      <guid>https://dev.to/simerplaha/hash-index-swaydb-4k8</guid>
      <description>&lt;h1&gt;
  
  
  Hash-index @ SwayDB
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Hash-indexes improves random read performance by 55%!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PpHDUxK7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/o2ewd1yb2cghbrc083jr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PpHDUxK7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/o2ewd1yb2cghbrc083jr.png" alt="Hash-index-performance-bar-chart" width="762" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hash-indexes like &lt;code&gt;HashSet&lt;/code&gt; or &lt;code&gt;HashMap&lt;/code&gt; are useful for serving random read requests. They increase performance for randomly accessed data, reduce total number of IOps and save CPU time. But they can also be costly for applications that &lt;strong&gt;rarely&lt;/strong&gt; do random reads like &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time-series&lt;/strong&gt; or &lt;strong&gt;event-source&lt;/strong&gt; data might only require fast sequential reads. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold storage&lt;/strong&gt; or &lt;strong&gt;archived data&lt;/strong&gt; might not require random reads at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A configurable hash-index is required for &lt;a href="https://swaydb.simer.au/configurations/randomKeyIndex/?language=java/"&gt;SwayDB&lt;/a&gt; so various data storage requirements could be handled. The following were the requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Optionally enable or disable hash-index.&lt;/li&gt;
&lt;li&gt;Allow creation of perfect or nearly perfect hash-indexes.&lt;/li&gt;
&lt;li&gt;Create partially indexed hash-indexes with fallback to alternative indexes like binary-search &amp;amp; linear-search.&lt;/li&gt;
&lt;li&gt;Copy keys directly into the hash-index.&lt;/li&gt;
&lt;li&gt;Controlled concurrency.&lt;/li&gt;
&lt;li&gt;Compression.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example configuration
&lt;/h2&gt;

&lt;p&gt;The following creates a persistent &lt;code&gt;Map&lt;/code&gt; where hash-index is disabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
  &lt;span class="nc"&gt;MapConfig&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;functionsOff&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myMap"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;intSerializer&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;stringSerializer&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRandomKeyIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RandomKeyIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Optional[one]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following enables hash-index (&lt;code&gt;RandomKeyIndex&lt;/code&gt;) with custom configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
  &lt;span class="nc"&gt;MapConfig&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;functionsOff&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myMap"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;intSerializer&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;stringSerializer&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRandomKeyIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
      &lt;span class="nc"&gt;RandomKeyIndex&lt;/span&gt;  
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxProbe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//re-hash 10 times to resolve hash collision&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minimumNumberOfKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//minimum keys required&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minimumNumberOfHits&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//minimum indexed keys required &lt;/span&gt;
        &lt;span class="c1"&gt;//use reference format. IndexFormat.copyKeys() can also be used here&lt;/span&gt;
        &lt;span class="c1"&gt;//to copy keys directly into the hash-index&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;indexFormat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IndexFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reference&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allocateSpace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
          &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RandomKeyIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RequiredSpace&lt;/span&gt; &lt;span class="n"&gt;optimalSpace&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;//allocates 3 times more storage than the &lt;/span&gt;
            &lt;span class="c1"&gt;//default optimal space for higher hit rate. &lt;/span&gt;
            &lt;span class="n"&gt;optimalSpace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requiredSpace&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;   
         &lt;span class="o"&gt;)&lt;/span&gt;  
         &lt;span class="c1"&gt;//allow async IO for all IO operations&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ioStrategy&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;IOAction&lt;/span&gt; &lt;span class="n"&gt;ioAction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOStrategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AsyncIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  
         &lt;span class="c1"&gt;//Use LZ4 and fallback to Snappy.&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compression&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;UncompressedBlockInfo&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;  
          &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
             &lt;span class="c1"&gt;//try running LZ4 with minimum 20.0% compression    &lt;/span&gt;
            &lt;span class="nc"&gt;Compression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lz4Pair&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
              &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LZ4Instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fastestInstance&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LZ4Compressor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Fast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;  
              &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LZ4Instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fastestInstance&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;LZ4Decompressor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fastDecompressor&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;  
            &lt;span class="o"&gt;),&lt;/span&gt;  
            &lt;span class="c1"&gt;//if LZ4 fails try Snappy with 20.0% compression.    &lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Compression&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Snappy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
         &lt;span class="o"&gt;)&lt;/span&gt;  
       &lt;span class="o"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Optional[one]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a detail documentation of the configurations refer to &lt;a href="https://swaydb.simer.au/configurations/randomKeyIndex/?language=java/"&gt;documentation&lt;/a&gt; website. &lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB"&gt;SwayDB&lt;/a&gt;  on GitHub.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.java.examples"&gt;Java&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.kotlin.examples"&gt;Kotlin&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/simerplaha/SwayDB.scala.examples"&gt;Scala&lt;/a&gt;  examples repo.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://swaydb.simer.au/"&gt;Documentation website&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>scala</category>
      <category>persistent</category>
      <category>storage</category>
    </item>
    <item>
      <title>Intro to SwayDB</title>
      <dc:creator>Simer Plaha</dc:creator>
      <pubDate>Sat, 08 Feb 2020 13:57:21 +0000</pubDate>
      <link>https://dev.to/simerplaha/intro-to-swaydb-51cm</link>
      <guid>https://dev.to/simerplaha/intro-to-swaydb-51cm</guid>
      <description>&lt;p&gt;&lt;a href="https://swaydb.simer.au"&gt;SwayDB&lt;/a&gt; is an embeddable persistent and in-memory key-value store/database.&lt;/p&gt;

&lt;p&gt;Here I will try to demonstrate on how to create a &lt;code&gt;Map&lt;/code&gt; in Scala and play with some basic APIs to do simple CRUD operations.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating a Map
&lt;/h1&gt;

&lt;p&gt;You can ignore &lt;code&gt;Nothing&lt;/code&gt; and &lt;code&gt;Bag.Less&lt;/code&gt; for now which will explained in future posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;swaydb._&lt;/span&gt; &lt;span class="c1"&gt;//swaydb's APIs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;swaydb.serializers.Default._&lt;/span&gt; &lt;span class="c1"&gt;//default serialisers&lt;/span&gt;

&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;map&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;, &lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Bag.Less&lt;/span&gt;&lt;span class="o"&gt;]().&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt; &lt;span class="c1"&gt;//create a memory map&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly a persistent &lt;code&gt;Map&lt;/code&gt; can be created by replacing &lt;code&gt;memory.Map&lt;/code&gt; with &lt;code&gt;persistent.Map&lt;/code&gt; and providing a folder name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;map&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;persistent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;, &lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Bag.Less&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"target/myMap"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Basic Put &amp;amp; Get
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//returns Some("one")&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Expiring &amp;amp; Updating data
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;//put and expire after 1 hour&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"two"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expireAfter&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;//updates value but leave the expiration unchanged.&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"two updated"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//returns expiration deadline.&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;expiration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Remove/Deleting data
&lt;/h2&gt;

&lt;p&gt;Batch removes both keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;//return true - Map is now empty.&lt;/span&gt;
&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;isEmpty&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://scastie.scala-lang.org/simerplaha/eXfalgt2RNmBG3cXxe4uKQ/3"&gt;Run on Scastie&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Done!&lt;/p&gt;

</description>
      <category>scala</category>
      <category>memory</category>
      <category>persistent</category>
      <category>storage</category>
    </item>
  </channel>
</rss>
