Skip to content

[IcebergIO] Fix stale openWriters count in RecordWriterManager - #39157

Merged
ahmedabu98 merged 1 commit into
apache:masterfrom
atognolag:u3-cleanup-fix
Jun 29, 2026
Merged

[IcebergIO] Fix stale openWriters count in RecordWriterManager#39157
ahmedabu98 merged 1 commit into
apache:masterfrom
atognolag:u3-cleanup-fix

Conversation

@atognolas

Copy link
Copy Markdown
Contributor

Summary

  • Add writers.cleanUp() before the openWriters >= maxNumWriters capacity check in RecordWriterManager.DestinationState.write()
  • Guava Cache eviction is lazy — expired entries are only removed on subsequent access or explicit cleanUp(), not proactively
  • Without this fix, openWriters stays stale after writers expire, causing 100% false spill for tables with more partitions than maxNumWriters (default 20)

Motivation

With DEFAULT_MAX_WRITERS_PER_BUNDLE = 20 and more than 20 partitions, every record for the 21st+ partition is rejected as if the writer pool is full, triggering the spill path. Observed on a 400-partition table: 100% of records spilled, causing disk exhaustion.

After the fix, expired writers are properly evicted before the capacity check, and spill only occurs when the pool is genuinely full.

Test plan

  • Existing RecordWriterManagerTest passes
  • Run IcebergIO integration tests with >20 partitions
  • Verify spill rate drops to near-zero for tables with idle partitions

🤖 Generated with Claude Code

RecordWriterManager uses a Guava Cache with expireAfterAccess(1 min)
for writer eviction. However, Guava Cache eviction is lazy — expired
entries are only removed on subsequent access or explicit cleanUp().
The write() method checks `openWriters >= maxNumWriters` without first
calling cleanUp(), so expired writers remain in the cache and
openWriters stays stale.

With DEFAULT_MAX_WRITERS_PER_BUNDLE = 20 and more than 20 partitions,
this causes 100% false spill — every record for the 21st+ partition
is rejected as if the writer pool is full.

Add writers.cleanUp() before the capacity check to evict expired
entries and update openWriters accurately.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a bug in the IcebergIO RecordWriterManager where stale writer counts caused premature spilling. By forcing a cache cleanup before evaluating the maximum writer capacity, the system now correctly identifies available slots, preventing unnecessary disk usage when handling tables with many partitions.

Highlights

  • Guava Cache Cleanup: Added an explicit call to writers.cleanUp() within the RecordWriterManager.DestinationState.write() method to ensure expired writers are removed before capacity checks.
  • Capacity Check Logic: Updated the writer capacity check to re-verify the openWriters count after cache cleanup, preventing false spill triggers.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies the RecordWriterManager to call writers.cleanUp() when the open writers limit is reached, attempting to free up space before rejecting a write. The review feedback highlights that calling cleanUp() on every write attempt under limit pressure can cause significant CPU overhead and lock contention, and suggests rate-limiting these cleanup calls.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 165 to 170
if (writer == null && openWriters >= maxNumWriters) {
return false;
writers.cleanUp();
if (openWriters >= maxNumWriters) {
return false;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Calling writers.cleanUp() on every single write attempt that results in a spill can introduce significant CPU overhead and lock contention, especially when processing a large volume of records for partitions that exceed maxNumWriters. Since Guava's cleanUp() acquires locks on all cache segments, calling it repeatedly in a tight loop for every spilled record is inefficient.\n\nTo optimize this, consider rate-limiting the cleanUp() calls (e.g., at most once every second) by tracking the last cleanup time using a timestamp field (e.g., lastCleanupNanos) in DestinationState.\n\nNote: You will need to define private long lastCleanupNanos = 0L; as a field in the DestinationState class for this suggestion to compile.

      if (writer == null && openWriters >= maxNumWriters) {\n        long now = System.nanoTime();\n        if (now - lastCleanupNanos > 1000000000L) {\n          writers.cleanUp();\n          lastCleanupNanos = now;\n        }\n        if (openWriters >= maxNumWriters) {\n          return false;\n        }\n      }

@atognolas

Copy link
Copy Markdown
Contributor Author

@ahmedabu98 — Would you mind reviewing this? These are a set of IcebergIO fixes validated on production-scale benchmarks (39M users, 400 partitions, 99-column schema). The four PRs are independent and can be reviewed/merged in any order.

@github-actions

Copy link
Copy Markdown
Contributor

Checks are failing. Will not request review until checks are succeeding. If you'd like to override that behavior, comment assign set of reviewers

@ahmedabu98 ahmedabu98 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ahmedabu98

Copy link
Copy Markdown
Contributor

Failing test is an unrelated flake (#19480). Merging

@ahmedabu98
ahmedabu98 merged commit 961ed7c into apache:master Jun 29, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants