<?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: Mohd Saquib Mansoori</title>
    <description>The latest articles on DEV Community by Mohd Saquib Mansoori (@mohdsaquib114).</description>
    <link>https://dev.to/mohdsaquib114</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%2F1089594%2F2b178d3d-c08a-4764-80d4-ee8dd7fdfe4e.jpeg</url>
      <title>DEV Community: Mohd Saquib Mansoori</title>
      <link>https://dev.to/mohdsaquib114</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohdsaquib114"/>
    <language>en</language>
    <item>
      <title>Map First, Walk Second: What a Librarian Taught Me About Postgres</title>
      <dc:creator>Mohd Saquib Mansoori</dc:creator>
      <pubDate>Mon, 20 Jul 2026 16:39:48 +0000</pubDate>
      <link>https://dev.to/mohdsaquib114/map-first-walk-second-what-a-librarian-taught-me-about-postgres-di9</link>
      <guid>https://dev.to/mohdsaquib114/map-first-walk-second-what-a-librarian-taught-me-about-postgres-di9</guid>
      <description>&lt;p&gt;A few weeks back I was staring at an &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; output, feeling pretty good about myself. I knew the two big scan types — Seq Scan and Index Scan — and I thought that covered it. Full table, or use the index. Simple.&lt;/p&gt;

&lt;p&gt;Then I ran a query and saw this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bitmap Index Scan
Bitmap Heap Scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two lines I didn't recognize. My first reaction was to just ignore it and move on — but that never sits right with me, so I went down the rabbit hole. What I found actually changed how I think about databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picture a librarian, not a computer
&lt;/h2&gt;

&lt;p&gt;Here's the mental model that finally made it click for me.&lt;/p&gt;

&lt;p&gt;Imagine you ask a librarian for every book about "Engineering." A librarian doing an &lt;strong&gt;Index Scan&lt;/strong&gt; would work like this: check the catalog, walk to shelf 12, grab the book, walk back, check the catalog again, walk to shelf 47, grab the next book, walk back... For 10 books, that's fine. For 10,000 books scattered across the building? You'd fire that librarian.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Seq Scan&lt;/strong&gt; librarian does the opposite — ignores the catalog entirely and just walks every single shelf in the building, checking every book. Wasteful if you only needed a handful, but honestly not bad if you needed &lt;em&gt;most&lt;/em&gt; of the books anyway.&lt;/p&gt;

&lt;p&gt;Then there's the librarian who does something smarter. Before walking anywhere, they sit down with the catalog and write out a full list: "shelf 4, shelf 9, shelf 9 again, shelf 12, shelf 30." &lt;em&gt;Then&lt;/em&gt; they walk the building once, in order, picking up every book along the way without doubling back.&lt;/p&gt;

&lt;p&gt;That third librarian is a &lt;strong&gt;Bitmap Scan&lt;/strong&gt;. And once I saw it that way, the Postgres version stopped feeling abstract.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Postgres is actually doing
&lt;/h2&gt;

&lt;p&gt;It happens in two acts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Act one — Bitmap Index Scan.&lt;/strong&gt; Postgres goes through the index, but instead of fetching rows as it finds them, it just marks down &lt;em&gt;where&lt;/em&gt; the matches live — a simple map of "yes, this page has something I need." No data is touched yet. Just the map.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Act two — Bitmap Heap Scan.&lt;/strong&gt; Now Postgres walks the actual table, but it follows that map in physical order instead of chasing matches one by one. Fewer detours, fewer random jumps, way less wasted motion.&lt;/p&gt;

&lt;p&gt;That's it. That's the whole trick — &lt;em&gt;look before you leap, and leap in order.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more than it sounds
&lt;/h2&gt;

&lt;p&gt;Random disk access is one of the slowest things a database can do. Every time it jumps somewhere new, there's a cost. So Postgres' planner is constantly asking: "is this query going to touch so few rows that random jumping is fine? Or so many rows that I should just read everything? Or is it somewhere annoyingly in the middle?"&lt;/p&gt;

&lt;p&gt;That "annoying middle" is exactly where bitmap scans live. Say you've got a million employees and you're looking for everyone in Engineering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Engineering'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Only a tiny sliver of the table matches? Index Scan — a few random jumps are cheap enough.&lt;/li&gt;
&lt;li&gt;About 15% of the table matches? Bitmap Scan — too many for random jumps, too few to justify reading it all.&lt;/li&gt;
&lt;li&gt;More than half the table matches? Seq Scan — at that point, just read everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The part that actually impressed me
&lt;/h2&gt;

&lt;p&gt;Here's what made me sit up, though. Bitmaps aren't limited to one index — Postgres can build &lt;em&gt;two&lt;/em&gt; of them and merge them before ever touching the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Engineering'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One bitmap from the &lt;code&gt;department&lt;/code&gt; index, one from the &lt;code&gt;salary&lt;/code&gt; index, combined with a quick AND — and only &lt;em&gt;then&lt;/em&gt; does it go fetch rows. A regular index scan has no clean way to do that. This, to me, is the real reason bitmap scans exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  One honest caveat
&lt;/h2&gt;

&lt;p&gt;A bitmap only tells Postgres which pages to check — it still has to visit the table and confirm each row is actually visible (thanks to how MVCC works under the hood). And if the matching set is so big the bitmap can't track individual rows anymore, Postgres quietly downgrades to tracking whole &lt;em&gt;pages&lt;/em&gt; instead. You'll spot this in the plan as &lt;code&gt;Recheck Cond&lt;/code&gt; — Postgres double-checking the condition itself once it gets to the page, since the bitmap only promised "something here," not "this exact row."&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I landed
&lt;/h2&gt;

&lt;p&gt;I used to think "index = automatically fast." Turns out that's only true when few rows match. Once the number of matches climbs, blindly following the index becomes its own kind of slow — and that's the gap bitmap scans are built to fill.&lt;/p&gt;

&lt;p&gt;So next time &lt;code&gt;Bitmap Index Scan&lt;/code&gt; shows up in your &lt;code&gt;EXPLAIN&lt;/code&gt;, don't skim past it. It's Postgres quietly doing the librarian thing — mapping first, walking second.&lt;/p&gt;

</description>
      <category>database</category>
      <category>performance</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Transactions Behind the Scenes: What Really Happens in a Database</title>
      <dc:creator>Mohd Saquib Mansoori</dc:creator>
      <pubDate>Tue, 14 Jul 2026 07:00:05 +0000</pubDate>
      <link>https://dev.to/mohdsaquib114/transactions-behind-the-scenes-what-really-happens-in-a-database-5d9f</link>
      <guid>https://dev.to/mohdsaquib114/transactions-behind-the-scenes-what-really-happens-in-a-database-5d9f</guid>
      <description>&lt;h2&gt;
  
  
  What Actually Happens When You Hit COMMIT
&lt;/h2&gt;

&lt;p&gt;I used to think of &lt;code&gt;COMMIT&lt;/code&gt; as a light switch. You flip it, the data is saved, done. It wasn't until I actually dug into how Postgres handles a transaction internally that I realized how much engineering is packed into that one keyword — and how much of it exists purely to survive the worst possible moment: your server crashing mid-write.&lt;/p&gt;

&lt;p&gt;This post is my attempt to explain that process the way I wish someone had explained it to me — with a real multi-table example, not a toy one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a real scenario
&lt;/h2&gt;

&lt;p&gt;Say we're running a small e-commerce backend with three tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A user places an order. In your application code this probably happens inside a single DB transaction, something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'placed'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'debit'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three separate writes, but they need to succeed or fail together. If the balance gets deducted but the order never gets recorded, you've got a very confused customer and a support ticket. This is exactly what a transaction is for — a group of operations that the database treats as one atomic unit, guaranteeing the classic ACID properties: atomicity, consistency, isolation, and durability.&lt;/p&gt;

&lt;p&gt;But "guaranteeing durability" is doing a lot of work in that sentence. How does the database actually make sure committed data survives a crash a millisecond later? That's the interesting part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nothing happens directly on disk
&lt;/h2&gt;

&lt;p&gt;The first thing that surprised me: none of those three statements touch your disk directly. Disk I/O is slow — genuinely, painfully slow compared to RAM — so Postgres (like basically every serious database) keeps a chunk of memory called the &lt;strong&gt;buffer cache&lt;/strong&gt; (or buffer pool) where it pulls in the relevant data pages before touching them.&lt;/p&gt;

&lt;p&gt;So when the &lt;code&gt;UPDATE&lt;/code&gt; runs, Postgres loads the page containing user &lt;code&gt;id = 1&lt;/code&gt;'s row into the buffer cache, and modifies it &lt;em&gt;there&lt;/em&gt;. Same for the new rows going into &lt;code&gt;orders&lt;/code&gt; and &lt;code&gt;transactions&lt;/code&gt;. At this point, the data on disk is completely unaware anything has changed. The only place these changes exist is in memory, and technically only in the database's memory — your terminal, your app, everything else has no idea either.&lt;/p&gt;

&lt;p&gt;These modified-but-not-yet-saved pages have a name: &lt;strong&gt;dirty pages&lt;/strong&gt;. It's a slightly dramatic term for "we changed this in RAM but haven't written it back yet," but it's the term you'll see in every Postgres internals doc, so it's worth knowing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that actually protects you: WAL
&lt;/h2&gt;

&lt;p&gt;Here's the problem this creates: if the server loses power right now, those dirty pages evaporate. RAM doesn't survive a crash. So how does a &lt;code&gt;COMMIT&lt;/code&gt; ever mean anything?&lt;/p&gt;

&lt;p&gt;The answer is &lt;strong&gt;Write-Ahead Logging&lt;/strong&gt;, usually just called WAL. Before Postgres considers a transaction committed, it writes a compact record of exactly what changed to a log file — not the data pages themselves, just enough information to redo the change later. Something conceptually like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TXN 101:
- users.balance: 1000 → 500
- orders: new row inserted
- transactions: new row inserted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This log entry first lands in a small WAL buffer in memory too. So at this point you might reasonably ask: if the log is also just sitting in memory, what have we actually gained?&lt;/p&gt;

&lt;p&gt;This is the detail that took me a while to really internalize: &lt;strong&gt;when you run &lt;code&gt;COMMIT&lt;/code&gt;, Postgres doesn't write your dirty data pages to disk. It writes the WAL entry to disk, and calls &lt;code&gt;fsync&lt;/code&gt; to force the OS to physically flush it — not just hand it to a write buffer, but actually get it onto the storage device.&lt;/strong&gt; Only once that fsync succeeds does Postgres tell your application "commit successful."&lt;/p&gt;

&lt;p&gt;The dirty pages themselves — the actual &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, and &lt;code&gt;transactions&lt;/code&gt; rows — can sit in memory for a while longer. That's the trick. Writing one small sequential log entry is much cheaper than writing several scattered data pages, so WAL lets Postgres give you durability guarantees fast without paying the cost of a full page flush on every single commit.&lt;/p&gt;

&lt;p&gt;So the rule that actually matters is this: &lt;strong&gt;a commit is a promise that the WAL entry is safely on disk — not that your table's data pages are.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What crash recovery actually looks like
&lt;/h2&gt;

&lt;p&gt;This log-first approach is also exactly what makes recovery possible. Two scenarios worth walking through:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The server crashes before COMMIT finishes.&lt;/strong&gt; The WAL entry never made it to disk, and the dirty pages were only ever in memory. Both are gone. When Postgres restarts, it finds no trace of transaction 101 anywhere, so as far as the database is concerned, that transaction never happened. Your app would have seen the crash and (hopefully) never gotten a success response, so this is actually the "safe" failure — nothing inconsistent, nothing half-applied.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The server crashes after COMMIT succeeds, but before the dirty pages are flushed to disk.&lt;/strong&gt; Now the WAL entry &lt;em&gt;is&lt;/em&gt; safely on disk, but the actual table pages might not be yet. On restart, Postgres reads the WAL, finds transaction 101 marked complete, and replays those changes against the data files — a step called &lt;strong&gt;REDO&lt;/strong&gt;. Because the log already told it exactly what changed, it doesn't need to guess or ask your application to resend anything. The database ends up in the same state it would have been in if it had flushed everything immediately, just via a slightly delayed path.&lt;/p&gt;

&lt;p&gt;This is really the whole point of WAL: it turns "did my expensive multi-page write survive the crash" into "did my one small log entry survive the crash," which is a much easier problem to solve reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checkpoints: cleaning up so recovery stays fast
&lt;/h2&gt;

&lt;p&gt;If Postgres kept every dirty page in memory forever and only ever relied on WAL replay, the log would grow without bound, and a crash after weeks of uptime could mean replaying an enormous amount of history on restart. That's where &lt;strong&gt;checkpoints&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;Periodically (Postgres does this on a timer and also based on how much WAL has accumulated), it writes all the current dirty pages from memory out to disk for real, then marks a point in the WAL saying, essentially, "everything before this line is now safely reflected in the data files." Anything before that checkpoint no longer needs to be replayed during recovery — only WAL written after the last checkpoint matters.&lt;/p&gt;

&lt;p&gt;This is the mechanism that keeps crash recovery from turning into a multi-hour ordeal on a busy production database. Without it, restart time would grow in proportion to how long the server had been running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting the whole flow together
&lt;/h2&gt;

&lt;p&gt;Strip away the terminology and the sequence for our order example looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The relevant rows for &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, and &lt;code&gt;transactions&lt;/code&gt; are pulled into the buffer cache.&lt;/li&gt;
&lt;li&gt;Each row gets modified in memory, becoming a dirty page.&lt;/li&gt;
&lt;li&gt;Before commit, a WAL entry describing these changes is written.&lt;/li&gt;
&lt;li&gt;On &lt;code&gt;COMMIT&lt;/code&gt;, that WAL entry (not the data pages) is fsync'd to disk. The transaction is now durable.&lt;/li&gt;
&lt;li&gt;At some point later — could be seconds, could be during the next checkpoint — the dirty pages themselves get flushed to disk.&lt;/li&gt;
&lt;li&gt;If a crash happens in between, Postgres uses the WAL to redo whatever didn't make it to the data files yet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A path most systems don't take: shadow paging
&lt;/h2&gt;

&lt;p&gt;It's worth knowing there's an entirely different strategy some older or specialized systems use instead of WAL, called &lt;strong&gt;shadow paging&lt;/strong&gt;. Rather than modifying pages in place and logging the change, the database writes an entirely new copy of the page with the changes applied, leaving the original untouched. Commit is then just a matter of atomically swapping a pointer from the old page to the new one.&lt;/p&gt;

&lt;p&gt;It's conceptually simpler in some ways — no REDO or UNDO logic needed, since the old version is still sitting there intact until the swap happens. But it comes at a real cost: every update means duplicating a page rather than modifying it, which gets expensive fast in terms of both storage and I/O once you're dealing with high write volume. That's part of why WAL-based approaches won out in most mainstream relational databases, Postgres included.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is worth actually understanding
&lt;/h2&gt;

&lt;p&gt;You can build plenty of features without ever thinking about buffer pools or fsync calls. But the moment something goes sideways in production — a pod gets OOM-killed mid-transaction, a disk fills up, a deploy restarts the DB at the wrong second — knowing what's actually guaranteed at each stage is the difference between confidently saying "that data is safe" and just hoping it is.&lt;/p&gt;

&lt;p&gt;That gap, more than anything else, is what separates someone who runs queries against a database from someone who actually understands what it's doing underneath them.&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>computerscience</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating a small project on Counting Using Bash Scripting</title>
      <dc:creator>Mohd Saquib Mansoori</dc:creator>
      <pubDate>Sat, 22 Jul 2023 10:00:07 +0000</pubDate>
      <link>https://dev.to/mohdsaquib114/creating-a-small-project-on-counting-using-bash-scripting-4c6d</link>
      <guid>https://dev.to/mohdsaquib114/creating-a-small-project-on-counting-using-bash-scripting-4c6d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Title: Building a Simple Timer Project Using Bash Scripting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introduction:&lt;/strong&gt;&lt;br&gt;
In the world of programming, mastering various languages is essential for expanding your skills and enhancing problem-solving abilities. Bash scripting is one such powerful tool that comes in handy for automating tasks, managing processes, and creating small projects. In this blog, we'll explore how to build a simple yet practical timer project using Bash scripting. Whether you're a beginner or an experienced developer, this project will not only be a fun challenge but also a great way to strengthen your Bash skills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;br&gt;
Before diving into the project, make sure you have basic knowledge of Bash scripting and a Linux or macOS environment. Bash is a popular shell and scripting language that comes pre-installed on most Unix-based systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Overview:&lt;/strong&gt;&lt;br&gt;
The goal of this project is to create a timer that allows users to set a specific time interval and receive a notification when the timer expires. We'll use the &lt;code&gt;sleep&lt;/code&gt; command to achieve this, along with some basic user input and output handling in Bash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Getting Started&lt;/strong&gt;&lt;br&gt;
To begin, open your terminal and create a new file called &lt;code&gt;timer.sh&lt;/code&gt; using your favorite text editor. This file will contain the Bash script that defines the timer's functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Setting the Timer&lt;/strong&gt;&lt;br&gt;
In this step, we'll ask the user to input the desired time interval for the timer. We'll use the &lt;code&gt;read&lt;/code&gt; command to prompt the user for input and store it in a variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Welcome to the Bash Timer!"&lt;/span&gt;

&lt;span class="c"&gt;# Ask the user to enter the time interval&lt;/span&gt;
&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Enter the time in seconds: "&lt;/span&gt; time_interval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Timer Logic&lt;/strong&gt;&lt;br&gt;
With the user's input, we'll implement the timer logic using the &lt;code&gt;sleep&lt;/code&gt; command. The &lt;code&gt;sleep&lt;/code&gt; command suspends the script's execution for a specified number of seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if the input is a positive integer&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$time_interval&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^[0-9]+&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: Please enter a positive integer."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Display a confirmation message to the user&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Timer set for &lt;/span&gt;&lt;span class="nv"&gt;$time_interval&lt;/span&gt;&lt;span class="s2"&gt; seconds. Press Ctrl+C to stop the timer."&lt;/span&gt;

&lt;span class="c"&gt;# Start the timer&lt;/span&gt;
&lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$time_interval&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Timer expires - display the notification&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Timer expired! Time's up!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Make the Script Executable&lt;/strong&gt;&lt;br&gt;
Before we can run the script, we need to make it executable using the &lt;code&gt;chmod&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x timer.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: Run the Timer&lt;/strong&gt;&lt;br&gt;
You're now ready to run the timer! Execute the script in your terminal by typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./timer.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;br&gt;
Congratulations! You've successfully built a simple timer project using Bash scripting. This project may seem modest, but it lays the groundwork for more complex and useful applications. Feel free to expand this project by adding features like sound notifications, multiple timers, or integrating it with other scripts. With Bash scripting, the possibilities are endless!&lt;/p&gt;

&lt;p&gt;Remember, practice is key to mastering any programming language. So, keep exploring, experimenting, and building more projects to enhance your skills and become a proficient developer.&lt;/p&gt;

&lt;p&gt;If there is any thing wrong or is not correct, let me know.&lt;/p&gt;

</description>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
