iceberg: create missing metadata parent directories exclusively

saveMetadataBlob created each missing directory on the way to the metadata
directory with a plain CreateEntry after a lookup. A table directory another
create had made and written its record onto since the lookup was replaced by a
bare directory, erasing that record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chris LuandClaude Opus 5.5 committed 2026-11-12 20:19:18 -08:00
1 parent 712af663d1
commit 03e2dbb40e
2 files changed
+23 -1

No files matched your search

@@ -940,6 +940,26 @@ func TestFinalizeCreateOnCommitLosesToTableWithoutLocation(t *testing.T) {
e.assertWinnerRecord("", winnerUUID)
}
// A table directory another create made and wrote its record onto after this
// writer's lookup missed it keeps that record when a metadata file is staged.
func TestSaveMetadataBlobKeepsATableDirectoryCreatedSinceTheLookup(t *testing.T) {
e := newConflictEnv(t)
namespaceDir := path.Join(s3tables.TablesPath, conflictBucket, conflictNamespace)
record := `{"Name":"` + conflictTable + `"}`
e.hooks.beforeCreate = func(req *filer_pb.CreateEntryRequest) {
if req.Directory == namespaceDir && req.Entry.Name == conflictTable {
e.hooks.beforeCreate = nil
e.filer.Put(namespaceDir, conflictTable, map[string][]byte{s3tables.ExtendedKeyMetadata: []byte(record)})
}
}
if err := e.server.saveMetadataBlob(t.Context(), conflictBucket, path.Join(conflictNamespace, conflictTable), "v1.metadata.json", []byte("{}"), "application/json", true, nil); err != nil {
t.Fatalf("save metadata: %v", err)
}
if got := e.filer.Get(namespaceDir, conflictTable); got == nil || string(got.Extended[s3tables.ExtendedKeyMetadata]) != record {
t.Errorf("table record replaced by the directory create: %+v", got)
}
}
// Two stage-create commits for one name: one creates the table and the other is
// told it lost, and the file the catalog points at belongs to the winner.
func TestConcurrentFinalizeCreateOnCommitHasOneWinner(t *testing.T) {
+3 -1
View File
@@ -68,9 +68,11 @@ func (s *Server) saveMetadataBlob(ctx context.Context, bucketName, tablePath, me
return fmt.Errorf("lookup %s failed: %w", errorContext, err)
}
// If lookup fails with ErrNotFound, try to create the directory.
// Exclusive, so a directory created since the lookup keeps the
// record a table create may have written onto it.
resp, createErr := client.CreateEntry(opCtx, &filer_pb.CreateEntryRequest{
Directory: parent,
OExcl: true,
Entry: &filer_pb.Entry{
Name: name,
IsDirectory: true,