From 302d7fdbf3dc59ed8ef6a2e25c0b052435009cb0 Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Thu, 9 May 2024 16:35:20 -0700 Subject: [PATCH] prune partial downloads (#4272) --- server/images.go | 35 +++++++++++++++++++++-------------- server/modelpath.go | 3 --- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/server/images.go b/server/images.go index 2be1d366..3f415b6d 100644 --- a/server/images.go +++ b/server/images.go @@ -565,7 +565,7 @@ func CreateModel(ctx context.Context, name, modelFileDir, quantization string, m } if !envconfig.NoPrune { - if err := deleteUnusedLayers(nil, unref, false); err != nil { + if err := deleteUnusedLayers(nil, unref); err != nil { return err } } @@ -613,7 +613,7 @@ func CopyModel(src, dst model.Name) error { return err } -func deleteUnusedLayers(skipModelPath *ModelPath, deleteMap map[string]struct{}, dryRun bool) error { +func deleteUnusedLayers(skipModelPath *ModelPath, deleteMap map[string]struct{}) error { fp, err := GetManifestPath() if err != nil { return err @@ -660,13 +660,9 @@ func deleteUnusedLayers(skipModelPath *ModelPath, deleteMap map[string]struct{}, slog.Info(fmt.Sprintf("couldn't get file path for '%s': %v", k, err)) continue } - if !dryRun { - if err := os.Remove(fp); err != nil { - slog.Info(fmt.Sprintf("couldn't remove file '%s': %v", fp, err)) - continue - } - } else { - slog.Info(fmt.Sprintf("wanted to remove: %s", fp)) + if err := os.Remove(fp); err != nil { + slog.Info(fmt.Sprintf("couldn't remove file '%s': %v", fp, err)) + continue } } @@ -689,14 +685,25 @@ func PruneLayers() error { for _, blob := range blobs { name := blob.Name() name = strings.ReplaceAll(name, "-", ":") - if strings.HasPrefix(name, "sha256:") { - deleteMap[name] = struct{}{} + + _, err := GetBlobsPath(name) + if err != nil { + if errors.Is(err, ErrInvalidDigestFormat) { + // remove invalid blobs (e.g. partial downloads) + if err := os.Remove(filepath.Join(p, blob.Name())); err != nil { + slog.Error("couldn't remove blob", "blob", blob.Name(), "error", err) + } + } + + continue } + + deleteMap[name] = struct{}{} } slog.Info(fmt.Sprintf("total blobs: %d", len(deleteMap))) - err = deleteUnusedLayers(nil, deleteMap, false) + err = deleteUnusedLayers(nil, deleteMap) if err != nil { return err } @@ -752,7 +759,7 @@ func DeleteModel(name string) error { } deleteMap[manifest.Config.Digest] = struct{}{} - err = deleteUnusedLayers(&mp, deleteMap, false) + err = deleteUnusedLayers(&mp, deleteMap) if err != nil { return err } @@ -912,7 +919,7 @@ func PullModel(ctx context.Context, name string, regOpts *registryOptions, fn fu if noprune == "" { fn(api.ProgressResponse{Status: "removing any unused layers"}) - err = deleteUnusedLayers(nil, deleteMap, false) + err = deleteUnusedLayers(nil, deleteMap) if err != nil { return err } diff --git a/server/modelpath.go b/server/modelpath.go index 86908226..25a817ca 100644 --- a/server/modelpath.go +++ b/server/modelpath.go @@ -154,9 +154,6 @@ func GetBlobsPath(digest string) (string, error) { // only accept actual sha256 digests pattern := "^sha256[:-][0-9a-fA-F]{64}$" re := regexp.MustCompile(pattern) - if err != nil { - return "", err - } if digest != "" && !re.MatchString(digest) { return "", ErrInvalidDigestFormat