<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title></title>
    <atom:link href="https://byu.io/feed.xml" rel="self" type="application/rss+xml"/>
    <link>https://byu.io/</link>
    <description></description>
    <pubDate>Fri, 20 Sep 2024 06:49:33 +0000</pubDate>
    
      <item>
        <title>Why Transactions Are Good for You</title>
        <link>https://byu.io/2020/02/27/why-acid.html</link>
        <guid isPermaLink="true">https://byu.io/2020/02/27/why-acid.html</guid>
        <description>&lt;p&gt;Databases are magical and amazing pieces of software. If you don’t agree with me, &lt;a href=&quot;https://brandur.org/postgres-atomicity&quot;&gt;please&lt;/a&gt; &lt;a href=&quot;https://brandur.org/sortsupport&quot;&gt;let&lt;/a&gt; &lt;a href=&quot;https://brandur.org/http-transactions&quot;&gt;these&lt;/a&gt; &lt;a href=&quot;https://dataintensive.net/&quot;&gt;awesome&lt;/a&gt; &lt;a href=&quot;https://databass.dev/&quot;&gt;resources&lt;/a&gt; change your mind. In addition to being magical and amazing, they’re also mysterious and complex, using advanced data structures and algorithms to store data efficiently and handle concurrent access. I use databases all the time but am pretty much oblivious to how they work under the hood. Let’s fix that knowledge deficiency by getting down and dirty with a foundational concept of modern databases: &lt;strong&gt;transactions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the first part of a multi-part series of articles. Stay tuned for Part 2, in which we’ll begin building a simple transactional database from scratch! Let’s get started.&lt;/p&gt;

&lt;h3 id=&quot;what-the-hell-are-acid-transactions&quot;&gt;What the hell are ACID transactions?&lt;/h3&gt;

&lt;p&gt;You might have heard that ACID in database-land stands for Atomicity, Consistency, Isolation, and Durability. Those terms are fine and dandy, but what do they actually mean? ACID refers to properties of database &lt;strong&gt;&lt;em&gt;transactions&lt;/em&gt;&lt;/strong&gt;, which are indivisible units of work that a database executes. We’ll be going over transactions, each of the ACID properties, and why they’re important.&lt;/p&gt;

&lt;h3 id=&quot;what-happens-when-you-dont-have-acid&quot;&gt;What happens when you don’t have ACID&lt;/h3&gt;

&lt;p&gt;To better understand what transactions are, we need to first understand the problems they solve. Consider this Go function that withdraws money from a bank account. It does &lt;em&gt;not&lt;/em&gt; use database transactions to accomplish this.&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// withdraw decrements account balance by a specified amount.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;account %v not found: %w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Enforce constraint that balances cannot be negative.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;balance of %v for account %v is below $0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// return error if Put() fails&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This code works perfectly if only one thread is accessing the database at a time. However, we live in a world where concurrency abounds. Applications must handle requests concurrently to serve multiple users at the same time. What happens if we call &lt;code class=&quot;highlighter-rouge&quot;&gt;withdraw()&lt;/code&gt; from two threads (or goroutines) at the same time?&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Account &quot;brian&quot; initially has $100.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;brian&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;brian&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Now &quot;brian&quot; has $20???&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This code may result in a database access pattern that looks like this:&lt;/p&gt;

&lt;!-- ![race-condition](/img/acid/race-condition.png){: width=&quot;80%&quot;} --&gt;
&lt;center&gt;
    &lt;img src=&quot;/img/acid/race-condition.png&quot; width=&quot;80%&quot; /&gt;
&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;
In this example, &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_1&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_2&lt;/code&gt; withdraw a total of $150 from &lt;code class=&quot;highlighter-rouge&quot;&gt;brian&lt;/code&gt;’s original account balance of $100. Both calls to &lt;code class=&quot;highlighter-rouge&quot;&gt;withdraw()&lt;/code&gt; succeed and the final state of the database says that &lt;code class=&quot;highlighter-rouge&quot;&gt;brian&lt;/code&gt; has $20. Why?&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_1&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_2&lt;/code&gt; both read the original balance of &lt;code class=&quot;highlighter-rouge&quot;&gt;brian&lt;/code&gt; and then &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_1&lt;/code&gt; commits its updated balance. Soon after, &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_2&lt;/code&gt; commits its own updated balance. Since &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_1&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_2&lt;/code&gt; are unaware of each other’s actions, they both commit and the results of &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_1&lt;/code&gt; are overwritten by &lt;code class=&quot;highlighter-rouge&quot;&gt;Thread_2&lt;/code&gt;. In fancier, more technical terms, this is called a &lt;em&gt;lost update&lt;/em&gt; and is just one type of &lt;em&gt;write anomaly&lt;/em&gt;&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; that you are vulnerable to if you don’t use transactions.&lt;/p&gt;

&lt;p&gt;As soon as we introduce concurrency into our application, it becomes much harder to reason about database accesses. Each read or write to the database from different threads can be interleaved in any order, nondeterministically&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. The diagram above specifies just one of many ways those operations could have executed. If we’re lucky, both threads could run and work as expected, with one of the calls to &lt;code class=&quot;highlighter-rouge&quot;&gt;withdraw()&lt;/code&gt; returning an error. This nondeterminism is what makes concurrency bugs so insidious and hard to catch.&lt;/p&gt;

&lt;h3 id=&quot;how-transactions-help&quot;&gt;How transactions help&lt;/h3&gt;

&lt;p&gt;Transactions solve this by being &lt;strong&gt;&lt;em&gt;atomic&lt;/em&gt;&lt;/strong&gt;. They allow you to execute multiple operations together, as a single unit of work. Transactions guarantee that their operations will never be interleaved with those of another transaction that might conflict with it.&lt;/p&gt;

&lt;p&gt;Here’s what a transactional version of our &lt;code class=&quot;highlighter-rouge&quot;&gt;withdraw()&lt;/code&gt; function might look like&lt;sup id=&quot;fnref:badger&quot;&gt;&lt;a href=&quot;#fn:badger&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// withdraw decrements account balance by a specified amount.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Execute database transaction to atomically withdraw from account.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;txn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Txn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;account %v not found: %w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;// Constraint: can't have a negative balance!&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;balance of %v for account %v is below $0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// return error if Put() fails&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If we use transactions, &lt;code class=&quot;highlighter-rouge&quot;&gt;withdraw()&lt;/code&gt;’s &lt;code class=&quot;highlighter-rouge&quot;&gt;Get&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Put&lt;/code&gt; operations will always execute together. Thus, the prior example of conflicting calls to &lt;code class=&quot;highlighter-rouge&quot;&gt;withdraw()&lt;/code&gt; will always result in one of the calls failing. In other words, using transactions makes lost updates impossible! Hooray!&lt;/p&gt;

&lt;p&gt;In addition to atomicity, transactions offer other guarantees like consistency, isolation, and durability. Here are their definitions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Atomicity&lt;/strong&gt; – all steps of a transaction will finish successfully or none of them will. There will never be an “in-between” state that other transactions can see.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt; – a transaction can only cause the database to move from one valid state to another valid state. All database invariants and constraints defined by the user must be honored at all times. Consistency guarantees that databases cannot be corrupted by illegal transactions&lt;sup id=&quot;fnref:consistency&quot;&gt;&lt;a href=&quot;#fn:consistency&quot; class=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Isolation&lt;/strong&gt; – transactions can run without interference from any other concurrently executing transactions. The isolation level of a database controls both when and what changes to the database become visible to transactions. Isolation is heavily influenced by the database’s mechanism for &lt;a href=&quot;https://en.wikipedia.org/wiki/Concurrency_control#Concurrency_control_in_databases&quot;&gt;concurrency control&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Durability&lt;/strong&gt; – when a transaction commits, it will immediately write changes to persistent storage. If the database or machine crashes, the database can recover all committed changes from disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these properties work together to help ensure that modern databases maintain data integrity.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Yay! We learned a lot about ACID transactions and the types of bugs that they help prevent. That’s pretty good for one blog post, if you ask for my totally unbiased opinion :wink:.&lt;/p&gt;

&lt;p&gt;In Part 2 of this series, we’ll start building &lt;code class=&quot;highlighter-rouge&quot;&gt;lsdb&lt;/code&gt;, an in-memory key-value store that supports ACID transactions. We’ll learn how to implement transactions in code and explore &lt;a href=&quot;https://en.wikipedia.org/wiki/Multiversion_concurrency_control&quot;&gt;multiversion concurrency control&lt;/a&gt;, the concurrency control mechanism used in Postgres. Stay tuned!&lt;/p&gt;

&lt;!-- &lt;br/&gt;

Discuss this post on [HackerNews](https://news.ycombinator.com/item?id=22343870)! --&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://databass.dev&quot;&gt;Database Internals&lt;/a&gt; by Alex Petrov&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dataintensive.net&quot;&gt;Designing Data Intensive Applications&lt;/a&gt; by Martin Kleppmann&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;Other read and write anomalies that can occur include dirty reads, nonrepeatable reads, phantom reads, dirty writes, and write skew. You should look them up if you’re interested in them but they won’t be covered here for the sake of conciseness. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;The order is nondeterministic because thread execution is dictated by the operating system’s scheduler. If multiple threads are performing reads/writes at the same time, the order in which they execute is largely opaque to and uncontrollable by applications unless some sort of synchronization method is used. We’ll be covering &lt;em&gt;concurrency control&lt;/em&gt; methods in Part 2. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:badger&quot;&gt;
      &lt;p&gt;This syntax is inspired by &lt;a href=&quot;https://github.com/dgraph-io/badger&quot;&gt;BadgerDB&lt;/a&gt;, a database written in Go that supports ACID transactions. &lt;a href=&quot;#fnref:badger&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:consistency&quot;&gt;
      &lt;p&gt;Note that consistency does not guarantee the &lt;em&gt;correctness&lt;/em&gt; of the transactions that you write. Constraints here refer to things like &lt;code class=&quot;highlighter-rouge&quot;&gt;UNIQUE&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;NOT NULL&lt;/code&gt; in Postgres, not application logic constraints. &lt;a href=&quot;#fnref:consistency&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 27 Feb 2020 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Counting People with Machine Learning</title>
        <link>https://byu.io/2017/12/07/counting-people-with-ml.html</link>
        <guid isPermaLink="true">https://byu.io/2017/12/07/counting-people-with-ml.html</guid>
        <description>&lt;p&gt;I am a member of HackCville, a collective of UVA students and Charlottesville community members who are passionate about entrepreneurship, technology, and getting stuff done. This semester, I was a member of the Node, HC’s data science program (I’ll be a node TA next semester! HC is open to everyone, apply!). In order to become a fully fledged HackCville member, every program member must complete and present a final project using what they learned in their program. For my project, I chose to build a program that could track the number of people, via camera, at a place over time.&lt;/p&gt;

&lt;p&gt;[12/8/17] Note: Wow, this post really blew up on HackerNews! You can check out the discussion &lt;a href=&quot;https://news.ycombinator.com/item?id=15874866&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;brainstorming&quot;&gt;Brainstorming&lt;/h3&gt;

&lt;p&gt;I frequent &lt;a href=&quot;https://news.ycombinator.com&quot;&gt;HackerNews&lt;/a&gt;, and as any HN reader knows, machine learning and the internet of things are The Future and if you aren’t working in those areas you might as well not be working (/s!). So, I set out to find a project that combined these two topics in an interesting way. While brainstorming, I remembered a website that I had stumbled upon a few months ago: a directory of unsecured, internet connected webcams from all over the world called &lt;a href=&quot;http://www.insecam.org&quot;&gt;Insecam&lt;/a&gt;. Although I was initially creeped out by Insecam, I was fascinated with the idea that I could peer into so many different corners of the world just by clicking on a couple of links. I also remembered a cool neural network architecture that I had read about that achieved state of the art object detection, &lt;a href=&quot;https://pjreddie.com/darknet/yolo/&quot;&gt;YOLO&lt;/a&gt; (read the paper &lt;a href=&quot;https://arxiv.org/pdf/1612.08242.pdf&quot;&gt;here&lt;/a&gt;), which is built using the Darknet deep learning library. I thought it would be pretty cool if I could scrape data from Insecam and then process it using YOLO to gain some sort of insight. With that, I set out to analyze the frequency of people at certain locations using Python, Jupyter Notebooks, YOLO, and data from Insecam.&lt;/p&gt;

&lt;h3 id=&quot;scraping-video&quot;&gt;Scraping Video&lt;/h3&gt;

&lt;p&gt;First thing’s first, I had to figure out how to scrape data from Insecam. I first went on a hunt for an Insecam API, which unsurprisingly (due to Insecam’s sketchiness), did not exist. I then investigated each individual video stream and noticed that right clicking on each video frame and opening the link in a new tab brought me to each webcam’s IP address. Great! Now I had something that I could scrape. I first tried to use &lt;code class=&quot;highlighter-rouge&quot;&gt;wget&lt;/code&gt; to see if I could simply send a request and get a file. Unfortunately, &lt;code class=&quot;highlighter-rouge&quot;&gt;wget&lt;/code&gt; seemed to continuously download the video stream without ever stopping. I learned that most of these IP webcams streamed videos in &lt;a href=&quot;https://en.wikipedia.org/wiki/Motion_JPEG&quot;&gt;Motion JPEG&lt;/a&gt; and so I had to figure out a way to process it. Luckily, after some quick digging, I found that &lt;a href=&quot;https://opencv.org/&quot;&gt;OpenCV&lt;/a&gt; has a quick and easy &lt;code class=&quot;highlighter-rouge&quot;&gt;cv2.VideoCapture&lt;/code&gt; class that can pull image frames from mjpg video streams.&lt;/p&gt;

&lt;center&gt;
	&lt;img src=&quot;/img/counting-people/mjpg.png&quot; width=&quot;60%&quot; /&gt;
	&lt;p&gt;OpenCV to the rescue! A frame from an mJPG plotted in my Jupyter Notebook.&lt;/p&gt;
&lt;/center&gt;

&lt;h3 id=&quot;python-and-c-interop&quot;&gt;Python and C Interop&lt;/h3&gt;

&lt;p&gt;Next, I had to find out how to run Darknet, which is written in C, from Python. While some obvious choices would be to use FFI or to make a Python extension module, I didn’t want to get lost in the rabbit hole and spend days developing a Python extension, so I found a somewhat hacky solution: using the Python &lt;code class=&quot;highlighter-rouge&quot;&gt;subprocess&lt;/code&gt; library, I would run the YOLO executable on an image pulled from a webcam and then parse the console output from that executable to obtain the results. Using this strategy, I could get predicted objects and confidence data from YOLO quite easily. By counting the number of output lines with &lt;code class=&quot;highlighter-rouge&quot;&gt;person&lt;/code&gt; in them, I could get the number of people that YOLO thought were in the image frame at that instant in time. It was at this stage that I decided to analyze a &lt;a href=&quot;http://www.insecam.org/en/view/436615/&quot;&gt;small restaurant in Rotterdam&lt;/a&gt;.&lt;/p&gt;

&lt;center&gt;
	&lt;img src=&quot;/img/counting-people/ex1.png&quot; width=&quot;45%&quot; /&gt; &lt;img src=&quot;/img/counting-people/ex2.png&quot; width=&quot;45%&quot; /&gt;
	&lt;p&gt;Examples of YOLO running on images from the restaurant webcam.&lt;/p&gt;
&lt;/center&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cam.png: Predicted in 4.906712 seconds.
person: 61%
person: 56%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;center&gt;&lt;p&gt;Example output from the Darknet executable&lt;/p&gt;&lt;/center&gt;

&lt;h3 id=&quot;collecting-data-lots-of-it&quot;&gt;Collecting Data (Lots of it!)&lt;/h3&gt;

&lt;p&gt;Now that I had a means of obtaining the number of people at a given location based on webcam data, I wanted to collect a lot of data. Since I didn’t want to have to run YOLO on my laptop 24/7, I figured that the best way to collect data nonstop would be to write a quick and dirty &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;Flask&lt;/a&gt; server that could be deployed on a cheap VPS or AWS instance. In order to do this, I wrote two Python scripts. The first Python script continuously pulled image frames from the webcam, processed the frames with YOLO, and then appended the UNIX timestamp and number of people to a CSV file on the disk. The second script was a simple Flask server that hosted the &lt;a href=&quot;http://remote.byu.io:3000/cam&quot;&gt;raw webcam image&lt;/a&gt;, the &lt;a href=&quot;http://remote.byu.io:3000/predictions&quot;&gt;YOLO processed image&lt;/a&gt;, and the &lt;a href=&quot;http://remote.byu.io:3000/restaurant&quot;&gt;data log&lt;/a&gt;. Over the course of the week that I ran this experiment, I was able to collect over 55,000 data points, adding a new data point every 20 to 30 seconds.&lt;/p&gt;

&lt;h3 id=&quot;insights&quot;&gt;Insights&lt;/h3&gt;

&lt;p&gt;After collection over 55,000 data points, I loaded the file into a Jupyter Notebook and used Pandas and matplotlib to try and gain some insights from the data. I binned the data into windows of 5 minutes and averaged all data points withing those 5 minutes to account for variations in the number of people that YOLO counted. I then plotted the data in two ways. One plot showed the average number of people over the course of a single data and the other showed the number of people over the course of the week that I ran the experiment. It’s pretty cool how the data turned out– there is noticeable periodicity in the week graph and you can clearly see the number of people vary with closing hours and dinner time in the day graph. Pretty neat, if you ask me.&lt;/p&gt;

&lt;center&gt;
	&lt;img src=&quot;/img/counting-people/day.png&quot; width=&quot;60%&quot; /&gt;
	&lt;p&gt;Average number of people over the course of a day&lt;/p&gt;
&lt;/center&gt;

&lt;center&gt;
	&lt;img src=&quot;/img/counting-people/week.png&quot; width=&quot;60%&quot; /&gt;
	&lt;p&gt;Number of people over the course of a week&lt;/p&gt;
&lt;/center&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Overall, this little experiment turned out much better than expected. While the results themselves were unsurprising, I was surprised that YOLO was able to recognize people so well as to see noticeable periodicity over time that correlated with the closing hours and dinner spike of the restaurant. However, this project was far from perfect and there were some problems that could be improved with future work.&lt;/p&gt;
&lt;h4 id=&quot;problems--future-work&quot;&gt;Problems &amp;amp; Future Work&lt;/h4&gt;
&lt;p&gt;One major problem was that YOLO sometimes failed to detect people. Whether it be because of poor camera quality, bad lighting conditions, or a problem with YOLO, this may have caused the number of people recorded in the data to be artificially low. In future work, a convolutional neural network specifically trained to detect people could be used instead of YOLO, which is a pretrained convnet. Furthermore, a better user interface could be developed and a better camera could be used to perhaps turn this into a product that restaurant or property owners could use to keep track of foot traffic.&lt;/p&gt;
&lt;center&gt;
	&lt;img src=&quot;/img/counting-people/problem.png&quot; width=&quot;60%&quot; /&gt;
	&lt;p&gt;Oops! YOLO missed that whole group of people.&lt;/p&gt;
&lt;/center&gt;

&lt;h4 id=&quot;endnotes&quot;&gt;Endnotes&lt;/h4&gt;
&lt;p&gt;If you want to get this up and running on your machine, all the code is in a &lt;a href=&quot;https://github.com/brian-yu/pedestrian-cam&quot;&gt;Github repo&lt;/a&gt;. Just download and compile Darknet from the YOLO page, download the YOLO 2.0 &lt;a href=&quot;https://pjreddie.com/media/files/yolo.2.0.weights&quot;&gt;weights&lt;/a&gt; and then run both &lt;code class=&quot;highlighter-rouge&quot;&gt;prediction.py&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;server.py&lt;/code&gt;. Alternatively, you can look through the Jupyter notebook. Warning! This code is quite ugly, I will try to clean it up in the future.&lt;/p&gt;

&lt;p&gt;Any questions? Just shoot me an email!&lt;/p&gt;
</description>
        <pubDate>Thu, 07 Dec 2017 00:00:00 +0000</pubDate>
      </item>
    
  </channel>
</rss>
