<?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: Priyadarshan Singh</title>
    <description>The latest articles on DEV Community by Priyadarshan Singh (@pdrojack).</description>
    <link>https://dev.to/pdrojack</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%2F276613%2F4c2412c6-e946-4ff2-9b5a-85bddb3904ce.png</url>
      <title>DEV Community: Priyadarshan Singh</title>
      <link>https://dev.to/pdrojack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pdrojack"/>
    <language>en</language>
    <item>
      <title>How Redis Cut Memory Usage for Large Bitmaps with Native Roaring Compression</title>
      <dc:creator>Priyadarshan Singh</dc:creator>
      <pubDate>Wed, 14 Oct 2026 15:59:28 +0000</pubDate>
      <link>https://dev.to/pdrojack/how-redis-cut-memory-usage-for-large-bitmaps-with-native-roaring-compression-4e76</link>
      <guid>https://dev.to/pdrojack/how-redis-cut-memory-usage-for-large-bitmaps-with-native-roaring-compression-4e76</guid>
      <description>&lt;h1&gt;
  
  
  Why Bitmap Compression Matters in Redis
&lt;/h1&gt;

&lt;p&gt;Bitmaps are a fundamental data structure in Redis, used for everything from user tracking to analytics. Yet, before this change, Redis stored bitmaps as plain strings. This meant memory usage scaled with the highest bit set, not the number of bits actually set — a costly inefficiency for large or sparse bitmaps.&lt;/p&gt;

&lt;p&gt;If you’ve ever worked with large bitmaps in Redis, you know how quickly memory can balloon. This article dives into how Redis introduced native compressed bitmaps using the Roaring bitmap format to solve this problem, cutting memory usage dramatically without sacrificing performance or compatibility.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Problem: Dense Bitmap Storage Wastes Memory
&lt;/h1&gt;

&lt;p&gt;Redis represented bitmaps as strings where each byte corresponds to 8 bits, stretching out to the highest set bit. Imagine a bitmap with just a few bits set near the end of a large range — Redis still allocated memory for all bits up to that point.&lt;/p&gt;

&lt;p&gt;This dense representation is simple but inefficient for sparse or very large bitmaps. It results in wasted memory and can degrade performance due to increased memory pressure.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Root Cause: Lack of Compression or Sparse Representation
&lt;/h1&gt;

&lt;p&gt;The core issue was that Redis’s bitmap type had no concept of compression or sparse storage. It was a flat, byte-array representation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory allocated proportional to the highest bit offset.&lt;/li&gt;
&lt;li&gt;No differentiation between set and unset bits beyond the raw string.&lt;/li&gt;
&lt;li&gt;No ability to store bitmaps compactly when bits are few and far apart.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This meant that even a bitmap with a few scattered bits set could consume megabytes of memory if the highest set bit was large.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Solution: Integrating Roaring Bitmaps into Redis
&lt;/h1&gt;

&lt;p&gt;The PR introduces a new native bitmap type in Redis backed by the CRoaring library, a high-performance C implementation of Roaring bitmaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Roaring Bitmaps?
&lt;/h2&gt;

&lt;p&gt;Roaring bitmaps are a compressed bitmap format designed for fast operations and efficient memory usage, especially with sparse or clustered bitmaps. They achieve compression by splitting the bitmap into chunks and encoding each chunk using the most efficient method (arrays, bitmaps, or runs).&lt;/p&gt;

&lt;h2&gt;
  
  
  How Redis Uses Roaring Bitmaps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New Object Type:&lt;/strong&gt; A new Redis object type &lt;code&gt;OBJ_BITMAP&lt;/code&gt; with encoding &lt;code&gt;OBJ_ENCODING_BITMAP_ROARING&lt;/code&gt; is introduced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vendored CRoaring:&lt;/strong&gt; The PR vendors the CRoaring library to handle bitmap operations internally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Config Option:&lt;/strong&gt; A new configuration &lt;code&gt;bitmap-default-roaring&lt;/code&gt; allows automatic creation and conversion to Roaring bitmaps on writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command Compatibility:&lt;/strong&gt; Bit commands transparently work on both the old string bitmaps and new Roaring bitmaps, preserving existing semantics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence:&lt;/strong&gt; A new RDB type is added, leveraging CRoaring’s compact serialization format for efficient persistence and loading.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technical Integration Details
&lt;/h2&gt;

&lt;p&gt;The integration required careful handling to maintain compatibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type System:&lt;/strong&gt; Redis’s type system was extended to distinguish between string and Roaring bitmap encodings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command Layer:&lt;/strong&gt; Bit commands like &lt;code&gt;SETBIT&lt;/code&gt;, &lt;code&gt;GETBIT&lt;/code&gt;, and bitwise operations were adapted to dispatch to the appropriate underlying representation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversion Logic:&lt;/strong&gt; When &lt;code&gt;bitmap-default-roaring&lt;/code&gt; is enabled, writes create Roaring bitmaps by default. Existing string bitmaps can be converted lazily or eagerly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence:&lt;/strong&gt; The RDB format was extended to store Roaring bitmaps efficiently, avoiding the overhead of raw strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The Takeaway: Compression Requires Thoughtful Integration
&lt;/h1&gt;

&lt;p&gt;This change shows the power of choosing the right data structure for the job. Roaring bitmaps dramatically reduce memory usage for sparse or large bitmaps while preserving exact semantics.&lt;/p&gt;

&lt;p&gt;However, integrating compressed data structures into an existing system is non-trivial. It requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extending type systems to support multiple encodings.&lt;/li&gt;
&lt;li&gt;Ensuring command compatibility and seamless user experience.&lt;/li&gt;
&lt;li&gt;Supporting persistence formats that respect compression.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For engineers building high-performance systems, this PR is a great example of balancing new data structures’ benefits with the complexity of integration.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article is based on the Redis PR "Redis native compressed bitmaps (redis-roaring)". Read the full breakdown on nossletter.tech.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://nossletter.tech/digest/redis-15331-redis-native-compressed-bitmaps" rel="noopener noreferrer"&gt;Nossletter&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>redis</category>
      <category>bitmaps</category>
      <category>compression</category>
      <category>c</category>
    </item>
    <item>
      <title>Accelerating Regex Filtering in Milvus with FMIndex Candidate Pruning</title>
      <dc:creator>Priyadarshan Singh</dc:creator>
      <pubDate>Tue, 13 Oct 2026 16:25:46 +0000</pubDate>
      <link>https://dev.to/pdrojack/accelerating-regex-filtering-in-milvus-with-fmindex-candidate-pruning-4k8m</link>
      <guid>https://dev.to/pdrojack/accelerating-regex-filtering-in-milvus-with-fmindex-candidate-pruning-4k8m</guid>
      <description>&lt;h1&gt;
  
  
  Accelerating Regex Filtering in Milvus with FMIndex Candidate Pruning
&lt;/h1&gt;

&lt;p&gt;Regex filtering is a powerful tool for querying complex string patterns, but it can become a performance bottleneck when it requires scanning entire datasets. In Milvus, an open-source vector database, regex filtering on VARCHAR columns used to scan full row bytes even when the regex pattern contained selective literals that could help narrow down candidates. This article dives into a recent enhancement that leverages FMIndex candidate filtering to accelerate regex queries by extracting and utilizing multiple selective literals and their boolean relationships.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Inefficient Regex Filtering
&lt;/h2&gt;

&lt;p&gt;Before this change, Milvus’s regex filtering mechanism was suboptimal. It extracted only the longest literal substring from a regex pattern to generate candidate rows for filtering. While this might seem reasonable, it missed opportunities to use other selective literals embedded in the regex, especially when multiple literals were combined with AND/OR operators.&lt;/p&gt;

&lt;p&gt;For example, consider a regex pattern like &lt;code&gt;(foo|bar).*baz&lt;/code&gt;. The previous approach would extract just the longest literal (e.g., "baz") and ignore "foo" and "bar". This led to scanning all rows containing "baz," even though the presence of "foo" or "bar" could have further pruned candidates. Additionally, the regex filtering path did not integrate with the FMIndex candidate-and-recheck mechanism designed to efficiently filter rows based on indexed substrings.&lt;/p&gt;

&lt;p&gt;The consequence was that many regex queries triggered costly full scans over the data, reducing query performance and throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Root Cause
&lt;/h2&gt;

&lt;p&gt;The core issue was the simplistic extraction of only the longest literal substring from regex patterns. This approach failed to capture multiple selective literals and their boolean logic (AND/OR combinations) that could be leveraged for more effective candidate pruning.&lt;/p&gt;

&lt;p&gt;Moreover, the regex filtering path was disconnected from the FMIndex candidate filtering mechanism, which is capable of generating bitmap candidates based on indexed substrings. Without integrating these two, the system missed the chance to use FMIndex to prefilter rows before applying the expensive regex matching.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Integrating Regex Filtering with FMIndex Candidate Filtering
&lt;/h2&gt;

&lt;p&gt;This PR introduces a sophisticated method to route regex filtering on sealed VARCHAR columns through the existing FMIndex candidate-and-recheck path. The key enhancements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extraction of All Bounded Literals:&lt;/strong&gt; Instead of just the longest literal, the implementation extracts all bounded literals from the regex pattern while preserving their AND/OR relationships. This means that if the regex contains multiple literals combined with boolean operators, all are considered for candidate generation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Counting Distinct Literals per Segment:&lt;/strong&gt; The system counts distinct literals in each data segment to assess their selectivity and cost.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selecting Cheapest Literal Candidates per AND Group:&lt;/strong&gt; For each AND group in the boolean expression, it chooses the literal candidate with the lowest cost (i.e., the one expected to prune the most rows efficiently).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preserving OR Branches:&lt;/strong&gt; All OR branches are preserved to form combined candidate bitmaps, ensuring that rows matching any of the alternatives are considered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Canonical RE2 Regex Matcher for Final Recheck:&lt;/strong&gt; The RE2 regex matcher is compiled once and stored for reuse as a final recheck filter on candidate rows, ensuring correctness without redundant compilation overhead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FilteredRE2 Adapter:&lt;/strong&gt; A new adapter manages pinned RE2 prefilters with conservative structural checks to safely map literals extracted from regex patterns to FMIndex candidates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Thread-Local Cache:&lt;/strong&gt; To optimize performance, immutable preparations such as compiled regex and literal extraction are cached thread-locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preserving Input Bitmaps and NULL Validity:&lt;/strong&gt; The filtering preserves the original input bitmaps and NULL values, maintaining correctness in the presence of nullable data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Graceful Fallback:&lt;/strong&gt; When no usable literal candidates are found or the candidate generation budget is exceeded, the system falls back to scanning, ensuring robustness.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How This Works in Practice
&lt;/h3&gt;

&lt;p&gt;When a regex filter is applied on a sealed VARCHAR column, the system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parses the regex to identify all bounded literals and their boolean relationships.&lt;/li&gt;
&lt;li&gt;Uses the FMIndex to generate candidate bitmaps for these literals.&lt;/li&gt;
&lt;li&gt;Combines these bitmaps according to the AND/OR structure to form a precise candidate set.&lt;/li&gt;
&lt;li&gt;Applies the compiled RE2 matcher only to these candidates, avoiding full scans.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach effectively prunes the search space, reducing the number of rows that require expensive regex matching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway: The Power of Preserving Boolean Literal Relationships
&lt;/h2&gt;

&lt;p&gt;This enhancement highlights an important lesson in optimizing regex filtering with index structures: extracting and preserving multiple selective literals and their boolean relationships is crucial. Relying on a single longest literal can miss significant pruning opportunities.&lt;/p&gt;

&lt;p&gt;By integrating regex filtering with FMIndex candidate filtering and carefully managing the boolean logic of literals, Milvus achieves more precise candidate pruning and better query performance. This pattern can be applied to other systems where regex filtering and indexed substring search coexist.&lt;/p&gt;




&lt;p&gt;This article is based on the pull request "feat: accelerate regex filtering with FMIndex candidates" merged into the Milvus repository. Read the full breakdown on nossletter.tech.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://nossletter.tech/digest/milvus-53960-feat-accelerate-regex-filtering" rel="noopener noreferrer"&gt;Nossletter&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>milvus</category>
      <category>regex</category>
      <category>indexing</category>
      <category>performance</category>
    </item>
    <item>
      <title>Backporting Row-Level Security to Milvus 2.6: A Deep Dive into Enabling Fine-Grained Access Control</title>
      <dc:creator>Priyadarshan Singh</dc:creator>
      <pubDate>Mon, 12 Oct 2026 13:57:38 +0000</pubDate>
      <link>https://dev.to/pdrojack/backporting-row-level-security-to-milvus-26-a-deep-dive-into-enabling-fine-grained-access-control-2dih</link>
      <guid>https://dev.to/pdrojack/backporting-row-level-security-to-milvus-26-a-deep-dive-into-enabling-fine-grained-access-control-2dih</guid>
      <description>&lt;h1&gt;
  
  
  Why Row-Level Security Matters in Milvus 2.6
&lt;/h1&gt;

&lt;p&gt;Milvus, a popular vector database, thrives in scenarios requiring fast similarity search and analytics over large-scale vector data. With the rise of multi-tenant deployments and cloud-native architectures, enforcing &lt;strong&gt;fine-grained access control&lt;/strong&gt; becomes critical. Row-level security (RLS) allows administrators to restrict data access at the individual row level, ensuring users only see data they are authorized to access.&lt;/p&gt;

&lt;p&gt;Before this backport, Milvus 2.6 lacked RLS support, limiting its usability in secure, multi-tenant environments. This article explores the technical challenge of backporting the RLS feature from a newer Milvus version into 2.6, highlighting the intricacies of adapting modern security logic to an older codebase.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Problem: Missing Row-Level Security in Milvus 2.6
&lt;/h1&gt;

&lt;p&gt;Milvus 2.6 users faced a significant limitation: no ability to enforce row-level access policies during queries, data manipulation language (DML) operations, or bulk imports. This gap meant that all users with access to a collection could potentially retrieve or modify any data in it, violating the principle of least privilege.&lt;/p&gt;

&lt;p&gt;The original RLS implementation introduced in later Milvus versions depended on a set of APIs, data structures, and synchronization mechanisms absent in 2.6. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Advanced metadata management&lt;/strong&gt;: Newer versions use enhanced metadata stores to keep track of policies and tags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy synchronization&lt;/strong&gt;: Proxies maintain consistent snapshots of policies and tags to enforce security uniformly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy evaluation logic&lt;/strong&gt;: Complex evaluation engines determine whether a given user query or DML operation complies with RLS policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protobuf and import parsing&lt;/strong&gt;: Updated serialization formats and import mechanisms support richer policy data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These dependencies made a straightforward backport impossible, as 2.6's codebase lacked the necessary infrastructure.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Technical Solution: Backporting RLS with Compatibility
&lt;/h1&gt;

&lt;p&gt;The core challenge was to &lt;strong&gt;isolate the RLS feature set&lt;/strong&gt; from its newer dependencies and adapt it to fit within the constraints of Milvus 2.6. The backport involved several key technical steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Metadata Handling Adaptation
&lt;/h3&gt;

&lt;p&gt;RLS relies heavily on metadata to store policies and tags associated with rows. The backport reimplemented metadata handling using 2.6's existing storage and retrieval mechanisms, ensuring that policy data could be stored, updated, and queried without relying on newer metadata APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Proxy Synchronization Without New Membership Filters
&lt;/h3&gt;

&lt;p&gt;In newer versions, proxies synchronize policy and tag snapshots using advanced membership filters to maintain consistency. Since these filters were unavailable in 2.6, the backport introduced a synchronization mechanism compatible with the older proxy architecture, ensuring that all proxies had coherent views of the current policies and tags.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Policy Evaluation and Enforcement
&lt;/h3&gt;

&lt;p&gt;The evaluation engine was adapted to work with the older protobuf definitions and API constraints. This involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decoding policy tags correctly with 2.6's protobuf support.&lt;/li&gt;
&lt;li&gt;Validating policies in batches to minimize performance overhead.&lt;/li&gt;
&lt;li&gt;Recovering policy states gracefully after restarts or failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The enforcement logic was integrated into query processing, DML operations, and bulk imports, ensuring that row-level policies were consistently applied across all data access paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Maintaining Parser and Import Mechanisms
&lt;/h3&gt;

&lt;p&gt;To avoid regressions, the backport preserved 2.6’s existing parser and bulk import mechanisms. Instead of replacing these components, the RLS feature was carefully woven into the existing code paths, ensuring seamless integration without disrupting established workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Incorporating Fixes from the RLS7 Branch
&lt;/h3&gt;

&lt;p&gt;The backport included critical fixes originally developed in the RLS7 branch, such as tag decoding improvements, batch validation enhancements, and policy recovery strategies. These fixes were adapted to 2.6’s environment, ensuring parity in behavior with the master branch.&lt;/p&gt;




&lt;h1&gt;
  
  
  Lessons Learned: Backporting Complex Features Across Versions
&lt;/h1&gt;

&lt;p&gt;This backport illustrates several important lessons for engineering teams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decouple core logic from dependencies:&lt;/strong&gt; Successful backporting requires isolating feature logic from newer APIs and data structures, enabling adaptation to older environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapt serialization and parsing carefully:&lt;/strong&gt; Differences in protobuf versions and import formats can cause subtle bugs, so thorough testing and adjustment are essential.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preserve existing functionality:&lt;/strong&gt; Integrating new features should avoid disrupting established workflows, particularly in widely used components like parsers and importers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronize distributed components thoughtfully:&lt;/strong&gt; Proxy synchronization mechanisms must be compatible with the target version’s architecture to maintain consistency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By carefully balancing these factors, the Milvus team enabled secure, multi-tenant usage of 2.6 without sacrificing stability or performance.&lt;/p&gt;




&lt;p&gt;This article is based on the Milvus PR titled "feat: [2.6] backport row-level security" from the &lt;a href="https://github.com/milvus-io/milvus" rel="noopener noreferrer"&gt;milvus-io/milvus&lt;/a&gt; repository. Read the full breakdown on nossletter.tech.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://nossletter.tech/digest/milvus-53938-feat-2-6-backport" rel="noopener noreferrer"&gt;Nossletter&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>milvus</category>
      <category>security</category>
      <category>backport</category>
      <category>rowlevelsecurity</category>
    </item>
    <item>
      <title>How Airflow Handles Dynamic Task Executions with Immutable Dynamic Regions</title>
      <dc:creator>Priyadarshan Singh</dc:creator>
      <pubDate>Sun, 11 Oct 2026 18:57:47 +0000</pubDate>
      <link>https://dev.to/pdrojack/how-airflow-handles-dynamic-task-executions-with-immutable-dynamic-regions-4dcn</link>
      <guid>https://dev.to/pdrojack/how-airflow-handles-dynamic-task-executions-with-immutable-dynamic-regions-4dcn</guid>
      <description>&lt;h1&gt;
  
  
  Understanding Dynamic Task Executions in Apache Airflow
&lt;/h1&gt;

&lt;p&gt;Apache Airflow is a powerful platform for orchestrating complex workflows, but as workflows grow more dynamic—featuring loops, retries, and mapped tasks—tracking the state of each task execution becomes increasingly challenging. Have you ever wondered how Airflow internally distinguishes between multiple executions of the same task within dynamic constructs? This article dives into a recent improvement in Airflow’s core that introduces the concept of "dynamic regions" to solve this problem elegantly and efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Ambiguity in Tracking Dynamic Task Instances
&lt;/h2&gt;

&lt;p&gt;In Airflow, each task execution is represented by a Task Instance (TI), uniquely identified by a combination of &lt;code&gt;dag_id&lt;/code&gt;, &lt;code&gt;task_id&lt;/code&gt;, &lt;code&gt;run_id&lt;/code&gt;, and &lt;code&gt;map_index&lt;/code&gt;. This works well for static workflows where each task runs once per DAG run. However, with the rise of dynamic workflows—such as loops that execute a task multiple times or mapped tasks that spawn multiple parallel executions—this identification scheme falls short.&lt;/p&gt;

&lt;p&gt;Imagine a loop that runs the same task multiple times within a single DAG run. Because the task_id and run_id remain the same across iterations, Airflow cannot distinguish between these individual executions. This ambiguity leads to collisions in the database and makes it impossible to track retries or clears for distinct iterations correctly.&lt;/p&gt;

&lt;p&gt;Attempts to fix this by rewriting existing task instance rows to add more detailed identifiers proved impractical at production scale. Such rewrites would involve updating potentially millions of rows, leading to unacceptable downtime and performance degradation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Insight: Introducing Immutable Dynamic Regions
&lt;/h2&gt;

&lt;p&gt;To address this, the Airflow team introduced a new concept: &lt;strong&gt;dynamic regions&lt;/strong&gt;. Rather than trying to retrofit existing task instance identifiers, they created a dedicated, immutable database table to represent each execution context of dynamic constructs like loops or mapped tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Dynamic Region?
&lt;/h3&gt;

&lt;p&gt;A dynamic region encapsulates a logically distinct execution context within a DAG run. For example, each iteration of a loop or each batch of mapped tasks gets its own dynamic region. This means that instead of relying solely on &lt;code&gt;dag_id&lt;/code&gt;, &lt;code&gt;task_id&lt;/code&gt;, &lt;code&gt;run_id&lt;/code&gt;, and &lt;code&gt;map_index&lt;/code&gt;, task instances now reference a &lt;code&gt;region_id&lt;/code&gt; that explicitly disambiguates which dynamic execution they belong to.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Does This Work in Practice?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New Table:&lt;/strong&gt; A &lt;code&gt;dynamic_region&lt;/code&gt; table is added to the Airflow metadata database. Each row represents a unique dynamic execution context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutable Records:&lt;/strong&gt; Once created, a dynamic region record is immutable, ensuring consistency and simplifying reasoning about task executions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task Instance Reference:&lt;/strong&gt; The &lt;code&gt;task_instance&lt;/code&gt; table gains a foreign key reference to &lt;code&gt;dynamic_region.region_id&lt;/code&gt;. This allows multiple task instances with the same &lt;code&gt;task_id&lt;/code&gt; and &lt;code&gt;run_id&lt;/code&gt; to coexist without collision because they belong to different dynamic regions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Migration Strategy
&lt;/h3&gt;

&lt;p&gt;A critical challenge was migrating existing data without costly rewrites. To avoid long migration times, the implementation uses a sentinel zero value for the &lt;code&gt;region_id&lt;/code&gt; field in legacy task instances. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing task instances default to a &lt;code&gt;region_id&lt;/code&gt; of zero, preserving the old behavior.&lt;/li&gt;
&lt;li&gt;New dynamic executions get proper region IDs assigned.&lt;/li&gt;
&lt;li&gt;No extensive data rewriting is required, enabling a smooth transition at scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Matters: Lessons Learned
&lt;/h2&gt;

&lt;p&gt;This change highlights an important principle in evolving database schemas for complex, stateful systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Costly Data Rewrites:&lt;/strong&gt; Rewriting large volumes of existing data is often impractical in production environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Dedicated Entities for New Concepts:&lt;/strong&gt; Introducing a new immutable entity to represent dynamic execution contexts cleanly separates concerns and simplifies data integrity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Sentinel Values for Backward Compatibility:&lt;/strong&gt; This strategy enables incremental adoption without service disruption.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By embracing these principles, Airflow can now accurately track multiple executions of the same task within dynamic workflows, improving reliability and observability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The introduction of dynamic regions in Airflow represents a thoughtful and scalable approach to a subtle but impactful problem. By adding a dedicated immutable table to represent dynamic execution contexts, Airflow avoids the pitfalls of costly data migrations and enables precise tracking of complex task executions. This design pattern is a valuable example for any system dealing with evolving execution semantics and large-scale state management.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article is based on a recent pull request merged into the Apache Airflow repository. Read the full breakdown on nossletter.tech.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>apacheairflow</category>
      <category>databaseschema</category>
      <category>workfloworchestration</category>
      <category>dynamicexecution</category>
    </item>
  </channel>
</rss>
