in lib/blobrefresh/refresher.go [86:138]
func (r *Refresher) Refresh(namespace string, d core.Digest, hooks ...PostHook) error {
client, err := r.backends.GetClient(namespace)
if err != nil {
return fmt.Errorf("backend manager: %s", err)
}
// Always check whether the blob is actually available and valid before
// returning a potential pending error. This ensures that the majority of
// errors are propogated quickly and syncronously.
info, err := client.Stat(namespace, d.Hex())
if err != nil {
if err == backenderrors.ErrBlobNotFound {
return ErrNotFound
}
return fmt.Errorf("stat: %s", err)
}
size := datasize.ByteSize(info.Size)
if r.config.SizeLimit > 0 && size > r.config.SizeLimit {
return fmt.Errorf("%s blob exceeds size limit of %s", size, r.config.SizeLimit)
}
id := namespace + ":" + d.Hex()
err = r.requests.Start(id, func() error {
start := time.Now()
pieceLength := r.metaInfoGenerator.GetPieceLength(int64(size))
err := r.download(client, namespace, d, size.Bytes(), pieceLength)
if err != nil {
return err
}
t := time.Since(start)
stats := r.stats.Tagged(map[string]string{"namespace": extractPrefix(namespace)})
stats.Timer("download_remote_blob").Record(t)
stats.Counter("downloads").Inc(1)
log.With(
"namespace", namespace,
"name", d.Hex(),
"download_time", t).Info("Downloaded remote blob")
for _, h := range hooks {
h.Run(d)
}
return nil
})
switch err {
case dedup.ErrRequestPending:
return ErrPending
case backenderrors.ErrBlobNotFound:
return ErrNotFound
case dedup.ErrWorkersBusy:
return ErrWorkersBusy
default:
return err
}
}