Skip to content

fix(catalog): validate namespace existence in InMemoryCatalog create and register - #980

Open
LuciferYang wants to merge 2 commits into
apache:mainfrom
LuciferYang:fix/sweep-1-2-inmemory-namespace-validation
Open

LuciferYang wants to merge 2 commits into
apache:mainfrom
LuciferYang:fix/sweep-1-2-inmemory-namespace-validation

Conversation

@LuciferYang

@LuciferYang LuciferYang commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

What

InMemoryCatalog did not correctly check that a table's namespace exists, in two methods.

CreateTable wrote the table metadata file before validating the namespace. Creating a table under a missing namespace returned kNoSuchNamespace, but on object-store FileIO it first left an orphaned 00000-<uuid>.metadata.json that nothing later removes, and on the default local FileIO the stray write failed with a misleading kIOError.

RegisterTable guarded with if (!root_namespace_->NamespaceExists(identifier.ns)). NamespaceExists returns Result<bool>, so !result tests has_value() rather than the bool, and a missing namespace is a value false, not an error. The branch was dead code, and a missing namespace surfaced as kUnknownError instead of kNoSuchNamespace.

Closes #977.

How

CreateTable now validates the namespace before writing any metadata, matching SqlCatalog::CreateTable. RegisterTable reads the metadata outside the lock, then validates the namespace and registers under a single lock: the dead if (!NamespaceExists(...)) check (which tested the Result<bool>'s has_value() rather than the contained bool) becomes an unwrap that returns kNoSuchNamespace. Keeping the namespace check and the registration in one critical section leaves them atomic, and the metadata read stays off the lock. The empty (root) namespace still resolves to true, so ordinary table creation is unaffected.

Testing

Two new tests in in_memory_catalog_test.cc:

  • CreateTableNonexistentNamespace — creating a table under a missing namespace returns kNoSuchNamespace and leaves no metadata file behind. It passes an explicit location whose metadata/ directory already exists, so the pre-fix write lands a detectable orphan there; the zero-file assertion is what fails without the fix. The error-kind assertion alone would still pass pre-fix, because the later UpdateTableMetadataLocation also returns kNoSuchNamespace after the orphan is written.
  • RegisterTableNonexistentNamespace — registering under a missing namespace returns kNoSuchNamespace; without the fix the dead Result<bool> check let it fall through to kUnknownError.

Copilot AI balanced review requested due to automatic review settings October 1, 2026 11:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

RegisterTable still reads metadata before validating the namespace, allowing the wrong error to surface.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Validates namespaces in InMemoryCatalog table creation and registration to prevent orphan metadata and incorrect errors.

Changes:

  • Adds namespace checks to CreateTable and RegisterTable.
  • Adds regression tests for missing namespaces and orphan files.
File Description
src/​iceberg/​catalog/​memory/​in_memory_catalog.cc Adds namespace validation.
src/​iceberg/​test/​in_memory_catalog_test.cc Tests missing-namespace behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/iceberg/catalog/memory/in_memory_catalog.cc
@LuciferYang
LuciferYang force-pushed the fix/sweep-1-2-inmemory-namespace-validation branch from 753aec5 to dd3cf63 Compare October 1, 2026 14:31
Copilot AI balanced review requested due to automatic review settings October 1, 2026 14:31
@LuciferYang

Copy link
Copy Markdown
Contributor Author

Addressed the review note: RegisterTable now validates the namespace before reading the metadata, so registering into a missing namespace fails fast with NoSuchNamespace rather than surfacing a read error. The regression test now uses an unreadable metadata location to pin that ordering.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Registration now holds the exclusive catalog mutex during potentially slow metadata I/O.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (1)

Comment on lines +620 to +621
ICEBERG_ASSIGN_OR_RAISE(auto metadata,
TableMetadataUtil::Read(*file_io_, metadata_file_location));
…and register

CreateTable wrote the table metadata file before checking the namespace, leaking
an orphaned metadata file on object-store FileIO and returning a misleading
kIOError on local FileIO. RegisterTable's if (!NamespaceExists(...)) tested the
Result<bool>'s has_value() rather than the contained bool, so the
missing-namespace branch was dead code and the error surfaced as kUnknownError.

Both paths now unwrap NamespaceExists and return kNoSuchNamespace before any
metadata I/O: CreateTable before the write, RegisterTable before the read, so a
register into a missing namespace fails fast without a wasted (and possibly
failing) metadata read.
Copilot AI balanced review requested due to automatic review settings October 1, 2026 17:05
@LuciferYang
LuciferYang force-pushed the fix/sweep-1-2-inmemory-namespace-validation branch from dd3cf63 to ecefc10 Compare October 1, 2026 17:05
@LuciferYang

Copy link
Copy Markdown
Contributor Author

Follow-up on the lock note: RegisterTable now validates the namespace under a short-lived lock, releases it, reads the metadata outside the lock, then re-acquires the lock only to insert into the registry. The catalog mutex is no longer held across the metadata read, and the namespace is still validated before the read.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Registration has a namespace-validation race during concurrent namespace removal.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)

@LuciferYang

Copy link
Copy Markdown
Contributor Author

On the concurrent-namespace-removal note: the final root_namespace_->RegisterTable re-resolves the namespace under the lock before inserting, so a drop in the window between validation and insert makes the insert fail rather than registering into a missing namespace. The only effect is a less specific error kind in that rare race, and InMemoryCatalog is a not-for-production catalog.

Read the metadata outside the lock, then validate the namespace and register
under a single lock, rather than splitting validation and registration into two
critical sections. This keeps the check and insert atomic, so a concurrent
namespace drop cannot slip between them, and still never holds the catalog mutex
during metadata I/O.
Copilot AI balanced review requested due to automatic review settings October 1, 2026 17:58
@LuciferYang

Copy link
Copy Markdown
Contributor Author

Design note for the next review pass: I moved RegisterTable back to reading the metadata outside the lock and then validating the namespace and registering under a single lock. This keeps the namespace check and the insert atomic (no window for a concurrent namespace drop between them) while never holding the catalog mutex during metadata I/O, consistent with how LoadTable reads outside the lock. The tradeoff is that a register targeting a missing namespace reads the metadata before the check rejects it; for this in-memory catalog that discarded read is negligible, and I preferred it over splitting the check and the insert into two critical sections.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Registration still reads metadata before validating the namespace, and its test does not detect that ordering bug.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)

Comment on lines +195 to +199
ICEBERG_UNWRAP_OR_FAIL(auto metadata,
ReadTableMetadataFromResource("TableMetadataV2Valid.json"));
auto table_location = GenerateTestTableLocation(table_ident.name);
auto metadata_location = std::format("{}v1.metadata.json", table_location);
ASSERT_THAT(TableMetadataUtil::Write(*file_io_, metadata_location, *metadata), IsOk());

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: InMemoryCatalog skips the namespace existence check in CreateTable and RegisterTable

2 participants