storage: streamline ETag calculation

This commit introduces some helpers so that ETags can be calculated at
the same time that files get read or written. Besides looking nicer, it
should also help reduce lock contention around file access, as files do
not need to be opened twice anymore.
This commit is contained in:
Conrad Hoffmann 2024-11-07 17:50:09 +01:00
parent fe0a0d0d00
commit 665b206709
4 changed files with 89 additions and 54 deletions

58
storage/etag.go Normal file
View file

@ -0,0 +1,58 @@
package storage
import (
"crypto/sha1"
"encoding/base64"
"hash"
"io"
)
type ETagWriter struct {
io.Writer
output io.Writer
csum hash.Hash
}
// NewETagWriter creates a new io.Writer that pipes writes to the provided
// output while also calculating the contents ETag.
func NewETagWriter(output io.Writer) *ETagWriter {
csum := sha1.New()
return &ETagWriter{
output: io.MultiWriter(output, csum),
csum: csum,
}
}
func (e *ETagWriter) Write(p []byte) (n int, err error) {
return e.output.Write(p)
}
func (e *ETagWriter) ETag() string {
csum := e.csum.Sum(nil)
return base64.StdEncoding.EncodeToString(csum[:])
}
type ETagReader struct {
io.Reader
input io.Reader
csum hash.Hash
}
// NewETagReader creates a new io.Reader that pipes reads from the provided
// input while also calculating the contents ETag.
func NewETagReader(input io.Reader) *ETagReader {
csum := sha1.New()
return &ETagReader{
input: io.TeeReader(input, csum),
csum: csum,
}
}
func (e *ETagReader) Read(p []byte) (n int, err error) {
return e.input.Read(p)
}
func (e *ETagReader) ETag() string {
csum := e.csum.Sum(nil)
return base64.StdEncoding.EncodeToString(csum[:])
}