-
Notifications
You must be signed in to change notification settings - Fork 384
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Don't unnecessarily compute the blob digest in PutBlob
Introduce internal/putblobdigest.Digester to encapsulate the two alternatives, so that the PutBlob implementations only need to plug it in. Then use it throughout: let PutBlob use caller-provided digest values, if any (and they use the right algorithm). Signed-off-by: Miloslav Trmač <mitr@redhat.com>
- Loading branch information
Showing
9 changed files
with
171 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package putblobdigest | ||
|
||
import ( | ||
"io" | ||
|
||
"github.com/containers/image/v5/types" | ||
"github.com/opencontainers/go-digest" | ||
) | ||
|
||
// Digester computes a digest of the provided stream, if not known yet. | ||
type Digester struct { | ||
knownDigest digest.Digest // Or "" | ||
digester digest.Digester // Or nil | ||
} | ||
|
||
// newDigester initiates computation of a digest.Canonical digest of stream, | ||
// if !validDigest; otherwise it just records knownDigest to be returned later. | ||
// The caller MUST use the returned stream instead of the original value. | ||
func newDigester(stream io.Reader, knownDigest digest.Digest, validDigest bool) (Digester, io.Reader) { | ||
if validDigest { | ||
return Digester{knownDigest: knownDigest}, stream | ||
} else { | ||
res := Digester{ | ||
digester: digest.Canonical.Digester(), | ||
} | ||
stream = io.TeeReader(stream, res.digester.Hash()) | ||
return res, stream | ||
} | ||
} | ||
|
||
// DigestIfUnknown initiates computation of a digest.Canonical digest of stream, | ||
// if no digest is supplied in the provided blobInfo; otherwise blobInfo.Digest will | ||
// be used (accepting any algorithm). | ||
// The caller MUST use the returned stream instead of the original value. | ||
func DigestIfUnknown(stream io.Reader, blobInfo types.BlobInfo) (Digester, io.Reader) { | ||
d := blobInfo.Digest | ||
return newDigester(stream, d, d != "") | ||
} | ||
|
||
// DigestIfCanonicalUnknown initiates computation of a digest.Canonical digest of stream, | ||
// if a digest.Canonical digest is not supplied in the provided blobInfo; | ||
// otherwise blobInfo.Digest will be used. | ||
// The caller MUST use the returned stream instead of the original value. | ||
func DigestIfCanonicalUnknown(stream io.Reader, blobInfo types.BlobInfo) (Digester, io.Reader) { | ||
d := blobInfo.Digest | ||
return newDigester(stream, d, d != "" && d.Algorithm() == digest.Canonical) | ||
} | ||
|
||
// Digest() returns a digest value possibly computed by Digester. | ||
// This must be called only after all of the stream returned by a Digester constructor | ||
// has been successfully read. | ||
func (d Digester) Digest() digest.Digest { | ||
if d.digester != nil { | ||
return d.digester.Digest() | ||
} | ||
return d.knownDigest | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package putblobdigest | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"io/ioutil" | ||
"testing" | ||
|
||
"github.com/containers/image/v5/types" | ||
"github.com/opencontainers/go-digest" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var testData = []byte("test data") | ||
|
||
type testCase struct { | ||
inputDigest digest.Digest | ||
computesDigest bool | ||
expectedDigest digest.Digest | ||
} | ||
|
||
func testDigester(t *testing.T, constructor func(io.Reader, types.BlobInfo) (Digester, io.Reader), | ||
cases []testCase) { | ||
for _, c := range cases { | ||
stream := bytes.NewReader(testData) | ||
digester, newStream := constructor(stream, types.BlobInfo{Digest: c.inputDigest}) | ||
assert.Equal(t, c.computesDigest, newStream != stream, c.inputDigest) | ||
data, err := ioutil.ReadAll(newStream) | ||
require.NoError(t, err, c.inputDigest) | ||
assert.Equal(t, testData, data, c.inputDigest) | ||
digest := digester.Digest() | ||
assert.Equal(t, c.expectedDigest, digest, c.inputDigest) | ||
} | ||
} | ||
|
||
func TestDigestIfUnknown(t *testing.T) { | ||
testDigester(t, DigestIfUnknown, []testCase{ | ||
{ | ||
inputDigest: digest.Digest("sha256:uninspected-value"), | ||
computesDigest: false, | ||
expectedDigest: digest.Digest("sha256:uninspected-value"), | ||
}, | ||
{ | ||
inputDigest: digest.Digest("unknown-algorithm:uninspected-value"), | ||
computesDigest: false, | ||
expectedDigest: digest.Digest("unknown-algorithm:uninspected-value"), | ||
}, | ||
{ | ||
inputDigest: "", | ||
computesDigest: true, | ||
expectedDigest: digest.Canonical.FromBytes(testData), | ||
}, | ||
}) | ||
} | ||
|
||
func TestDigestIfCanonicalUnknown(t *testing.T) { | ||
testDigester(t, DigestIfCanonicalUnknown, []testCase{ | ||
{ | ||
inputDigest: digest.Digest("sha256:uninspected-value"), | ||
computesDigest: false, | ||
expectedDigest: digest.Digest("sha256:uninspected-value"), | ||
}, | ||
{ | ||
inputDigest: digest.Digest("unknown-algorithm:uninspected-value"), | ||
computesDigest: true, | ||
expectedDigest: digest.Canonical.FromBytes(testData), | ||
}, | ||
{ | ||
inputDigest: "", | ||
computesDigest: true, | ||
expectedDigest: digest.Canonical.FromBytes(testData), | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters