Avoid duplicated chain ID calculation in unpack

This PR optimizes the chain ID calculation in unpack so we
only (pre-)calculate the chain ID for layer_i exactly once,
by calling `identity.ChainIDs(diffIDs)`.

Currently in `unpack` for every layer_i, we calculate the chain id
of layer_i-1 and layer_i *repeatedly*. Because each
`identity.ChainID(diffIDs)` call involves:

1. Copy `diffIDs` to a new slice
2. Calculate chain ID for every index (by calling `ChainIDs(diffIDs)`)
3. Return the final one as result of `identity.ChainID(diffIDs)`.

This means, given an image with N layers, for every layer_i:

1. we create 2 new slices and copy the diffIDs sofar;
2. we're recalculating all chain IDs from layer_0 to layer_i-1 twice;
3. in total, the chain ID for layer_i is calculated 2 * (N - layer_i) times;

Signed-off-by: Jin Dong <djdongjin95@gmail.com>
This commit is contained in:
Jin Dong
2025-01-03 03:29:08 +00:00
parent 5e85064da0
commit 95f45541e4

View File

@@ -273,8 +273,6 @@ func (u *Unpacker) unpack(
a = unpack.Applier
cs = u.content
chain []digest.Digest
fetchOffset int
fetchC []chan struct{}
fetchErr chan error
@@ -285,10 +283,17 @@ func (u *Unpacker) unpack(
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// pre-calculate chain ids for each layer
chainIDs := make([]digest.Digest, len(diffIDs))
copy(chainIDs, diffIDs)
chainIDs = identity.ChainIDs(chainIDs)
doUnpackFn := func(i int, desc ocispec.Descriptor) error {
parent := identity.ChainID(chain)
chain = append(chain, diffIDs[i])
chainID := identity.ChainID(chain).String()
var parent string
if i > 0 {
parent = chainIDs[i-1].String()
}
chainID := chainIDs[i].String()
unlock, err := u.lockSnChainID(ctx, chainID, unpack.SnapshotterKey)
if err != nil {
@@ -312,7 +317,7 @@ func (u *Unpacker) unpack(
for try := 1; try <= 3; try++ {
// Prepare snapshot with from parent, label as root
key = fmt.Sprintf(snapshots.UnpackKeyFormat, uniquePart(), chainID)
mounts, err = sn.Prepare(ctx, key, parent.String(), opts...)
mounts, err = sn.Prepare(ctx, key, parent, opts...)
if err != nil {
if errdefs.IsAlreadyExists(err) {
if _, err := sn.Stat(ctx, chainID); err != nil {
@@ -424,7 +429,10 @@ func (u *Unpacker) unpack(
}).Debug("layer unpacked")
}
chainID := identity.ChainID(chain).String()
var chainID string
if len(chainIDs) > 0 {
chainID = chainIDs[len(chainIDs)-1].String()
}
cinfo := content.Info{
Digest: config.Digest,
Labels: map[string]string{