<?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: Alex Day</title>
    <description>The latest articles on DEV Community by Alex Day (@silvern47).</description>
    <link>https://dev.to/silvern47</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1112348%2F3303211a-d641-489a-99f2-1943a49f622a.jpg</url>
      <title>DEV Community: Alex Day</title>
      <link>https://dev.to/silvern47</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/silvern47"/>
    <language>en</language>
    <item>
      <title>Shrinking a materials database</title>
      <dc:creator>Alex Day</dc:creator>
      <pubDate>Sun, 09 Aug 2026 14:08:23 +0000</pubDate>
      <link>https://dev.to/silvern47/shrinking-a-materials-database-1g5i</link>
      <guid>https://dev.to/silvern47/shrinking-a-materials-database-1g5i</guid>
      <description>&lt;p&gt;Shrinking datasets is quite contextual. It depends on how the dataset is going to be used. Its the same concept as optimizing databases, based on the read/write patterns.&lt;br&gt;
PACLEC and Traffic Patterns are the key determining factors.&lt;/p&gt;

&lt;p&gt;Hosted on fly.io : &lt;a href="https://materials-db.fly.dev/" rel="noopener noreferrer"&gt;https://materials-db.fly.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The need for this was not to integrate with &lt;a href="https://next-gen.materialsproject.org/materials" rel="noopener noreferrer"&gt;another external API&lt;/a&gt; for retrieving information on different materials and not think about rate-limiting. This was made as a part of a bigger system: &lt;a href="https://ikouchiha47.github.io/p/b8e2c4/materials-science-notes/" rel="noopener noreferrer"&gt;Research Agent for Researchers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The materials trajectory database was around 12Gigs and is mostly used for training models like &lt;a href="https://github.com/CederGroupHub/chgnet" rel="noopener noreferrer"&gt;CHGNet&lt;/a&gt;. &lt;br&gt;
But I needed it only for responding to query on finding materials and it didn't need all the variations.&lt;/p&gt;

&lt;p&gt;The aim was to be able to serve it using my most loved database - sqlite, in under reasonable timeframe: &amp;lt;500ms.&lt;/p&gt;

&lt;p&gt;A detailed write up is provided in my blog: &lt;a href="https://ikouchiha47.github.io/2026/08/05/materialsdb-11gb-to-266mb.html" rel="noopener noreferrer"&gt;https://ikouchiha47.github.io/2026/08/05/materialsdb-11gb-to-266mb.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sqlite</category>
      <category>programming</category>
    </item>
    <item>
      <title>Scheduling concurrency</title>
      <dc:creator>Alex Day</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:36:13 +0000</pubDate>
      <link>https://dev.to/silvern47/scheduling-concurrency-9bd</link>
      <guid>https://dev.to/silvern47/scheduling-concurrency-9bd</guid>
      <description>&lt;p&gt;Have been trying to look at 3 different languages: Go, Kotlin, Elixir/Erlang mostly to understand their concurrency models.&lt;/p&gt;

&lt;p&gt;This article concerns mostly about Go's preemptive scheduling. Looking at the dense article on go: &lt;a href="https://go.googlesource.com/proposal/+/master/design/24543-non-cooperative-preemption.md" rel="noopener noreferrer"&gt;https://go.googlesource.com/proposal/+/master/design/24543-non-cooperative-preemption.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is what I understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before Go 1.14:  Cooperative preemption at function prologues&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go used compiler-inserted cooperative preemption points in function prologues up to and including Go 1.10. This means Go could only switch between concurrently-executing goroutines at specific points - and the compiler ensured that all local GC roots were known at those safe-points, enabling precise garbage collection.&lt;/p&gt;

&lt;p&gt;The problems this caused were real and serious. In really extreme cases, it could cause a program to halt entirely.&lt;/p&gt;

&lt;p&gt;For example, when a goroutine spinning on an atomic load starved out the goroutine responsible for setting that atomic.&lt;/p&gt;

&lt;p&gt;They tried to fix this by inserting preemption checks at loop back-edges (the obvious next step), but even their most efficient approach - called "fault-based preemption" - added a geomean slowdown of 7.8% on a large benchmark suite. &lt;/p&gt;

&lt;p&gt;It also had implementation downsides: it couldn't target specific threads or goroutines, was "sticky" in that they couldn't resume any loops until all loops were resumed, and interfered with debuggers.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Go 1.14+: Signal-based non-cooperative preemption&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Non-cooperative preemption switches between concurrent execution contexts without explicit preemption checks or assistance from those contexts - the same way modern operating systems switch between threads. Without this, a single poorly-behaved goroutine can wedge a Go application, much like how a single poorly-behaved application could wedge an entire OS.&lt;/p&gt;

&lt;p&gt;The mechanism: Go implements this by sending a POSIX signal to stop a running goroutine and capture its CPU state. If a goroutine is interrupted at a point that must be GC-atomic, the runtime simply resumes the goroutine and tries again later.&lt;/p&gt;

&lt;p&gt;Why SIGURG specifically? It meets all the criteria: it's passed through by debuggers by default, isn't used internally by libc in mixed Go/C binaries, can happen spuriously without consequences, and is extremely unlikely to be used by an application for its real meaning - since out-of-band data is basically unused, and because SIGURG doesn't report which socket has the condition, making it pretty useless for its original purpose.&lt;/p&gt;




&lt;p&gt;SIGURG is a different beast altogether, it sits at the intersection of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;OS signals&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compiler internals&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Runtime/GC Designs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It needs more reading. Will come back to that later.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>linux</category>
    </item>
    <item>
      <title>Rebuilding Sofle-choc on android</title>
      <dc:creator>Alex Day</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:34:28 +0000</pubDate>
      <link>https://dev.to/silvern47/rebuilding-sofle-choc-on-android-8n1</link>
      <guid>https://dev.to/silvern47/rebuilding-sofle-choc-on-android-8n1</guid>
      <description>&lt;p&gt;I built a custom Android keyboard. It got weird.&lt;/p&gt;

&lt;p&gt;A full IME - written in Kotlin, handling every keypress, suggestion, and cursor movement myself. The idea was to replicate the Sofle Choc split. Because.&lt;/p&gt;

&lt;p&gt;Here's what actually surprised me building it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backspace into a committed word is a whole thing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once a word is committed, the suggestion engine loses track of it. Backspacing into it looks like a new character to the IME. Getting autocomplete to pick up the fragment again meant wrapping three API calls in &lt;code&gt;beginBatchEdit&lt;/code&gt;/&lt;code&gt;endBatchEdit&lt;/code&gt; to stop the editor firing callbacks mid-operation. &lt;code&gt;AnySoftKeyboard&lt;/code&gt; does the same thing. Took me way too long to figure out why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next-word prediction is more interesting than I expected:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After every committed word, surface what probably comes next - T9 style, but without the hardware. Two layers: a static English seed (Norvig's bigram corpus, MIT licensed) and a personal layer that learns from your actual typing. The scoring uses temporal decay from &lt;code&gt;librime&lt;/code&gt; - recent use contributes a near-full boost, something you typed 1000 commits ago contributes almost nothing. Old habits fade. New ones take over within a few hundred keystrokes.&lt;/p&gt;

&lt;p&gt;Learned about bigrams, infigrams, suffix-array with binary search and a new shit called #beam_search from github.com/rime/librime&lt;/p&gt;

&lt;p&gt;Mixed language (Banglish, Hinglish) works without any language detection, kinda - the personal layer is just a string map. It doesn't care what language you're in. Again, ASK showed the way for MVP.&lt;/p&gt;

&lt;p&gt;The suggestion interface mirrors librime's Grammar pattern, context passes through the function call, not stored as shared mutable state. Took one refactor to get there but it cleaned up everything downstream.&lt;/p&gt;

&lt;p&gt;A seven part series on the same:&lt;br&gt;
&lt;a href="https://ikouchiha47.github.io/keyboard/" rel="noopener noreferrer"&gt;https://ikouchiha47.github.io/keyboard/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>android</category>
    </item>
  </channel>
</rss>
