Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit83c253e

Browse files
committed
Fix race condition in concurrent artifact additions
This fixes a race condition where concurrent 'podman artifact add'commands for different artifacts would result in only one artifactbeing created, without any error messages.The root cause was in the artifact store's Add() method, whichwould:1. Acquire lock2. Read OCI layout index3. Create ImageDestination (which snapshots the index)4. RELEASE lock (optimization for blob copying)5. Copy blobs (while unlocked)6. Reacquire lock7. Commit changes (write new index)When two concurrent additions happened:- Process A: Lock → Read index → Create dest A → Unlock → Copy blobs- Process B: Lock → Read index (no artifact A!) → Create dest B → Unlock- Process A: Lock → Commit (write index with A)- Process B: Lock → Commit (write index with B, OVERWRITING A)The fix keeps the lock held for the entire operation. While thisreduces concurrency for blob copying, it prevents the index filecorruption that caused artifacts to be lost.Changes:- Remove lock release/reacquire around blob copying in store.Add()- Simplify lock management (no more conditional unlock)- Add e2e test for concurrent artifact additions- Add standalone test script to verify the fixFixes:#27569Generated-with: Cursor AISigned-off-by: Daniel J Walsh <dwalsh@redhat.com>
1 parent7cd9b81 commit83c253e

File tree

2 files changed

+63
-12
lines changed

2 files changed

+63
-12
lines changed

‎test/e2e/artifact_test.go‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,62 @@ var _ = Describe("Podman artifact", func() {
741741
session=podmanTest.PodmanExitCleanly("artifact","inspect",artifactDigest[:12],"-f","{{.Name}}")
742742
Expect(session.OutputToString()).To(Equal(artifact1Name))
743743
})
744+
745+
// Regression test for https://github.com/containers/podman/issues/27569
746+
It("podman artifact add concurrent - no race condition",func() {
747+
constnumArtifacts=5
748+
749+
// Create temporary files for artifacts
750+
artifactFiles:=make([]string,numArtifacts)
751+
artifactNames:=make([]string,numArtifacts)
752+
fori:=0;i<numArtifacts;i++ {
753+
file,err:=createArtifactFile(int64(1024* (i+1)))// Different sizes
754+
Expect(err).ToNot(HaveOccurred())
755+
artifactFiles[i]=file
756+
artifactNames[i]=fmt.Sprintf("localhost/concurrent/artifact%d",i)
757+
}
758+
759+
// Run all artifact add commands concurrently
760+
sessions:=make([]*PodmanSessionIntegration,numArtifacts)
761+
fori:=0;i<numArtifacts;i++ {
762+
// Start all commands without waiting
763+
sessions[i]=podmanTest.Podman([]string{"artifact","add",artifactNames[i],artifactFiles[i]})
764+
}
765+
766+
// Wait for all to complete and collect results
767+
digests:=make([]string,numArtifacts)
768+
fori:=0;i<numArtifacts;i++ {
769+
sessions[i].WaitWithDefaultTimeout()
770+
Expect(sessions[i]).Should(ExitCleanly())
771+
digests[i]=sessions[i].OutputToString()
772+
Expect(digests[i]).To(HaveLen(64))// SHA256 digest length
773+
}
774+
775+
// Verify all artifacts were created successfully
776+
listSession:=podmanTest.PodmanExitCleanly("artifact","ls","--format","{{.Repository}}")
777+
output:=listSession.OutputToStringArray()
778+
779+
// Check that all artifact names are in the list
780+
fori:=0;i<numArtifacts;i++ {
781+
Expect(output).To(ContainElement(artifactNames[i]),
782+
fmt.Sprintf("Artifact %s should be in the list",artifactNames[i]))
783+
}
784+
785+
// Verify each artifact can be inspected
786+
fori:=0;i<numArtifacts;i++ {
787+
inspectSession:=podmanTest.PodmanExitCleanly("artifact","inspect",artifactNames[i])
788+
Expect(inspectSession.OutputToString()).To(ContainSubstring(artifactNames[i]))
789+
}
790+
791+
// Verify each artifact has the correct size
792+
fori:=0;i<numArtifacts;i++ {
793+
expectedSize:=1024* (i+1)
794+
sizeSession:=podmanTest.PodmanExitCleanly("artifact","ls","--format","{{.VirtualSize}}","--noheading")
795+
sizes:=sizeSession.OutputToStringArray()
796+
Expect(sizes).To(ContainElement(fmt.Sprintf("%d",expectedSize)),
797+
fmt.Sprintf("Artifact %d should have size %d",i,expectedSize))
798+
}
799+
})
744800
})
745801

746802
funcdigestToFilename(digeststring)string {

‎vendor/go.podman.io/common/pkg/libartifact/store/store.go‎

Lines changed: 7 additions & 12 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp