Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Additional Layer Store] Use TOCDigest as ID of each layer (patch for c/image) #2416

Merged
merged 2 commits into from
May 20, 2024

Conversation

ktock
Copy link
Contributor

@ktock ktock commented May 14, 2024

Needs: containers/storage#1924

This commit changes the store implementation to use TOCDigset as the ID of each layer. This ensures the runtime to pass TOCDigest to the FUSE backend everytime requiring a layer.

This commit modifies c/storage's LookupAdditionalLayer to receive a TOCDigest as one of the arguments. Then that TOCDigest is passed to Additional Layer Store as one of the path elements of the FUSE fs. For example, the extracted view of a layer diff contents is provided in the following path:

 <mountpoint>/base64(imageref)/<TOCDigest>/diff

Additional Layer Store implementation attempts lazy pulling of the layer that has the specified TOCDigest in the image.
If that image doesn't contain the layer matching to the TOCDigest, accessing to the layer directly results in an error.

Example draft implementation of Additional Layer Store is at containerd/stargz-snapshotter#1673

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

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

Thanks!

Just a very quick first skim.

storage/storage_dest.go Outdated Show resolved Hide resolved
storage/storage_src.go Show resolved Hide resolved
storage/storage_dest.go Outdated Show resolved Hide resolved
@ktock ktock force-pushed the store-tocdigest-id branch 2 times, most recently from 76644c2 to 773cb67 Compare May 15, 2024 01:06
@TomSweeneyRedHat
Copy link
Member

@ktock You're fighting some lint errors on this one.

@ktock ktock force-pushed the store-tocdigest-id branch from 773cb67 to a1e2fff Compare May 16, 2024 01:09
@ktock
Copy link
Contributor Author

ktock commented May 16, 2024

Thanks for the comment. Fixed the linter error.

if err != nil && !errors.Is(err, storage.ErrLayerUnknown) {
return false, private.ReusedBlob{}, fmt.Errorf(`looking for compressed layers with digest %q and labels: %w`, blobDigest, err)
} else if err == nil {
s.lockProtected.blobDiffIDs[blobDigest] = aLayer.UncompressedDigest()
s.lockProtected.blobAdditionalLayer[blobDigest] = aLayer
d := aLayer.TOCDigest()
Copy link
Collaborator

Choose a reason for hiding this comment

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

We have passed down the expected TOC digest in LookupAdditionalLayer. Would this ever return a different value? If so, what does that mean / what is the guaranteed relationship between the two TOCs?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Looking at the implementation in containerd/stargz-snapshotter#1673 , this seems to always return the digest that is used in the FUSE request, i.e. it is exactly the value we passed in … unless the FUSE server is old and does not return the value at all; and in that case we don’t want to use any layers in the ALS — the FUSE server would be looking up a layer with compressed (non-TOC) digest options.TOCDigest.

Copy link
Collaborator

Choose a reason for hiding this comment

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

#2428 modifies this to only trust options.TOCDigest (but to require the one from the ALS to match).

s.lockProtected.blobDiffIDs[blobDigest] = aLayer.UncompressedDigest()
s.lockProtected.blobAdditionalLayer[blobDigest] = aLayer
d := aLayer.TOCDigest()
if d == "" {
Copy link
Collaborator

Choose a reason for hiding this comment

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

When can this happen? Wouldn’t it be appropriate to pull the layer in the ordinary way, instead of failing?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Per the other comment, this can happen if the FUSE server is old and not expecting TOCs at all.

storage/storage_src.go Show resolved Hide resolved
return -1, fmt.Errorf("size for layer %q is unknown, failing getSize()", layerID)
}
if layer.UncompressedSize < 0 {
sum = 0
Copy link
Collaborator

Choose a reason for hiding this comment

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

This means that if there 3 layers, and the middle one has an unknown size, the total returned size of the image is… some value larger than the true size, but the particular value can AFAICS not be reasonably used for anything.

Why is that better than returning -1 to indicate “unknown”, or than returning an error? (One possible answer might be “Podman callers assume this always succeeds and returns a non--1 value, I didn’t check whether that’s the case. But I think, if that were true, the callers would need to be updated to deal with images where the size is unknown, instead.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

#2428 modifies this to treat the unknown-size layer as zero-size, while returning the size of the other components.

return -1, fmt.Errorf("size for layer %q is unknown, failing getSize()", layerID)
}
if layer.UncompressedSize < 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

If a TOC-identified layer can have UncompressedSize == -1, that breaks more assumptions. At least the LayersByTOCDigest path in tryReusingBlobAsPending is using the UncompressedSize value, and the value can’t be “unknown” on that path.

… but, also, note to self: is a new behavior of the AdditionalLayerStore code? We did previously assume that the blobDigest-identified ALS layers did have a valid UncompressedSize. Was that always broken?

Copy link
Collaborator

@mtrmac mtrmac May 20, 2024

Choose a reason for hiding this comment

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

The commit says

Layers from additional layer store possibly doesn't know the uncompressed size until it fully downloads the entire contents to the node.

but we collect all metadata at the time of layer creation (layerStore.PutAdditionalLayer reads AdditionalLayer.Info for that), and don’t update it afterwards. Does that mean that the UncompressedSize is typically not available?


Actually, in https://github.com/containerd/stargz-snapshotter/pull/1673/files , it is now reported always as -1.

Copy link
Collaborator

Choose a reason for hiding this comment

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

At least the LayersByTOCDigest path in tryReusingBlobAsPending is using the UncompressedSize value, and the value can’t be “unknown” on that path.

That’s actually fine because that is already conditional on UncompressedDigest != "", and that’s false for recent ALS layers.

Copy link
Collaborator

@mtrmac mtrmac May 20, 2024

Choose a reason for hiding this comment

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

… and I don’t know whether UncompressedSize was always returned with the older version of the FUSE server, but that’s not a concern going forward, anyway.

storage/storage_src.go Show resolved Hide resolved
ktock added 2 commits May 20, 2024 17:28
Layers from additional layer store possibly doesn't know the uncompressed size
until it fully downloads the entire contents to the node.

Signed-off-by: Kohei Tokunaga <[email protected]>
@mtrmac mtrmac force-pushed the store-tocdigest-id branch from a1e2fff to 52101a0 Compare May 20, 2024 15:28
Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

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

Merging now because otherwise c/image does not compile after the c/storage API change; and because, as of today, containerd/stargz-snapshotter#1673 is not merged, so we actually never create ALS layers after merging this, and most of the concerns become hypothetical (in the short term).

I’ll immediately follow up with a PR that mitigates some of the concerns, or at least adds explicit FIXMEs. That’s not to preclude any other work on improving those aspects, just to get us back to a production-ready state.

@mtrmac mtrmac merged commit cf26b3c into containers:main May 20, 2024
10 checks passed
@ktock ktock deleted the store-tocdigest-id branch May 20, 2024 23:46
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.

3 participants