<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5" -->

---
title: Commit Sequence Number (CSN) MVCC: Lock-Free Snapshot...
description: PolarDB replaced PostgreSQL's lock-heavy snapshot mechanism with a single monotonically increasing Commit Sequence Number (CSN), ported from an earlier PolarDB...
canonical: https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Commit Sequence Number (CSN) MVCC: Lock-Free Snapshot Acquisition | daily.dev
og:description: PolarDB replaced PostgreSQL's lock-heavy snapshot mechanism with a single monotonically increasing Commit Sequence Number (CSN), ported from an earlier PolarDB...
og:url: https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5
og:image: https://api.daily.dev/og/posts/CrO8gQEu5.png
og:image:alt: Commit Sequence Number (CSN) MVCC: Lock-Free Snapshot Acquisition
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Commit Sequence Number (CSN) MVCC: Lock-Free Snapshot Acquisition

**[Planet PostgreSQL](https://daily.dev/sources/planet-postgresql)** · 9 min read · 0 upvotes · 0 comments

## Summary

PolarDB replaced PostgreSQL's lock-heavy snapshot mechanism with a single monotonically increasing Commit Sequence Number (CSN), ported from an earlier PolarDB generation onto the PostgreSQL 17 codebase. The new GetSnapshotDataCSN() reads atomic variables instead of scanning the ProcArray under the global ProcArrayLock, turning visibility checks into one integer comparison. CSN is enabled by default via polar_csn_enable. The port surfaced several silent correctness bugs: a missing memory barrier that could make transactions between two CSNs appear visible, a suboverflowed snapshot list that dropped running XIDs, and a standby that trusted a stale PD_ALL_VISIBLE bit during recovery. Six smaller fixes addressed serialization, truncation, and fallback logic.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://postgr.es/p/9zX>

## Questions this post answers

### What is Commit Sequence Number (CSN) based MVCC in PolarDB and how does it differ from PostgreSQL's default snapshot mechanism?

CSN MVCC replaces PostgreSQL's default snapshot representation, a list of in-flight transaction IDs captured under the global ProcArrayLock, with a single monotonically increasing number assigned to each transaction at commit. Visibility becomes one comparison: a transaction's commit CSN less than the snapshot's CSN means the tuple is visible. GetSnapshotDataCSN() acquires snapshots by reading atomic variables, avoiding ProcArrayLock entirely, and CSN is enabled by default via polar_csn_enable.

_Evaluating MVCC and snapshot isolation tradeoffs for Postgres-based systems is easier with sources tracked on daily.dev._

### Why did PostgreSQL's ProcArrayLock become a bottleneck for snapshot acquisition under high concurrency?

ProcArrayLock is a single global lock taken once per snapshot to walk the ProcArray and build a list of in-flight transaction IDs, so every backend taking a snapshot contends for the same lock. As concurrency grows, snapshot acquisition time and contention grow with it, turning it into a genuine throughput ceiling, and the cost scales with the number of concurrent transactions rather than the amount of data read.

_Developers tuning high-concurrency OLTP workloads can keep tabs on lock contention fixes like this via daily.dev._

### What correctness bugs can occur when implementing CSN-based snapshot visibility without PostgreSQL's traditional XID-list approach?

Several silent, crash-free wrong-answer bugs surfaced: missing a memory barrier between reading snapshot xmin and snapshotcsn let the CPU or compiler reorder the reads, making future transactions appear visible; a suboverflowed running-XID array silently dropped XIDs past its cutoff, causing a snapshot-isolation violation; and a standby snapshot builder failed to set takenDuringRecovery, letting scans trust a stale PD_ALL_VISIBLE bit and return rows it should not see.

_Teams building or auditing custom MVCC logic can track these edge-case fixes through daily.dev._

## Similar posts on daily.dev

- [PostgreSQL's MVCC is bad. So is everyone else's.](https://daily.dev/posts/postgresql-s-mvcc-is-bad-so-is-everyone-else-s--0puk6jb2f) · Planet PostgreSQL · 13 upvotes · 0 comments
- [Building a Linearizable Log on READ COMMITTED Isolation](https://daily.dev/posts/building-a-linearizable-log-on-read-committed-isolation-9mqmjrsxe) · Materialize · 0 upvotes · 0 comments
- [Database Transactions — PlanetScale](https://daily.dev/posts/database-transactions-planetscale-ubjf1ictb) · Hacker News · 1 upvotes · 0 comments

---

Tags: [#database](https://daily.dev/tags/database), [#postgresql](https://daily.dev/tags/postgresql)

[View this post on daily.dev](https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Commit Sequence Number (CSN) MVCC: Lock-Free Snapshot Acquisition","url":"https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5"},"datePublished":"2026-10-25T12:35:21.792Z","dateModified":"2026-10-25T12:36:02.506Z","description":"PolarDB replaced PostgreSQL's lock-heavy snapshot mechanism with a single monotonically increasing Commit Sequence Number (CSN), ported from an earlier PolarDB...","image":"https://media.daily.dev/image/upload/s--OHB84bZF--/f_auto/v1722860399/public/Placeholder%2010","thumbnailUrl":"https://media.daily.dev/image/upload/s--OHB84bZF--/f_auto/v1722860399/public/Placeholder%2010","isAccessibleForFree":true,"articleSection":"Planet PostgreSQL","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Planet PostgreSQL","logo":"https://media.daily.dev/image/upload/logos/placeholder.jpg","url":"https://daily.dev/sources/planet-postgresql"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"database,postgresql","timeRequired":"PT9M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Planet PostgreSQL","item":"https://daily.dev/sources/planet-postgresql"},{"@type":"ListItem","position":3,"name":"Commit Sequence Number (CSN) MVCC: Lock-Free Snapshot Acquisition"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/commit-sequence-number-csn-mvcc-lock-free-snapshot-acquisition-cro8gqeu5#faq","mainEntity":[{"@type":"Question","name":"What is Commit Sequence Number (CSN) based MVCC in PolarDB and how does it differ from PostgreSQL's default snapshot mechanism?","acceptedAnswer":{"@type":"Answer","text":"CSN MVCC replaces PostgreSQL's default snapshot representation, a list of in-flight transaction IDs captured under the global ProcArrayLock, with a single monotonically increasing number assigned to each transaction at commit. Visibility becomes one comparison: a transaction's commit CSN less than the snapshot's CSN means the tuple is visible. GetSnapshotDataCSN() acquires snapshots by reading atomic variables, avoiding ProcArrayLock entirely, and CSN is enabled by default via polar_csn_enable. Evaluating MVCC and snapshot isolation tradeoffs for Postgres-based systems is easier with sources tracked on daily.dev."}},{"@type":"Question","name":"Why did PostgreSQL's ProcArrayLock become a bottleneck for snapshot acquisition under high concurrency?","acceptedAnswer":{"@type":"Answer","text":"ProcArrayLock is a single global lock taken once per snapshot to walk the ProcArray and build a list of in-flight transaction IDs, so every backend taking a snapshot contends for the same lock. As concurrency grows, snapshot acquisition time and contention grow with it, turning it into a genuine throughput ceiling, and the cost scales with the number of concurrent transactions rather than the amount of data read. Developers tuning high-concurrency OLTP workloads can keep tabs on lock contention fixes like this via daily.dev."}},{"@type":"Question","name":"What correctness bugs can occur when implementing CSN-based snapshot visibility without PostgreSQL's traditional XID-list approach?","acceptedAnswer":{"@type":"Answer","text":"Several silent, crash-free wrong-answer bugs surfaced: missing a memory barrier between reading snapshot xmin and snapshotcsn let the CPU or compiler reorder the reads, making future transactions appear visible; a suboverflowed running-XID array silently dropped XIDs past its cutoff, causing a snapshot-isolation violation; and a standby snapshot builder failed to set takenDuringRecovery, letting scans trust a stale PD_ALL_VISIBLE bit and return rows it should not see. Teams building or auditing custom MVCC logic can track these edge-case fixes through daily.dev."}}]}
```

