From 7a01ad76143973199bd6965c13476d2d04f10f75 Mon Sep 17 00:00:00 2001 From: Blake Mizerany Date: Mon, 3 Mar 2025 19:11:16 -0800 Subject: [PATCH] server/internal/registry: reintroduce pruning on model deletion (#9489) This reintroduces aggressive pruning on model deletion as a temporary measure until a more controlled garbage collection (GC) mechanism is implemented. Issues with the current approach: 1. Users may accidentally delete a model (`ollama rm llama3.3` instead of `ollama rm llama3.2`), requiring a full re-download unless another model references the same blobs. 2. Users may assume a deleted model is still referenced elsewhere, but due to prior updates or deletions, the references no longer exist, leading to unnecessary re-downloads. Soon, we should implement a structured GC mechanism to retain unreferenced blobs for a configurable period before removal, which will run on "ollama rm" and other commands we deem appropriate. Users that want to immediately remove unreferenced blobs can use a new prune command that will allow them to specify the age and class of blobs to remove. Example usage: # Run basic blob GC $ ollama prune # Remove unreferenced blobs older than 7 days $ ollama prune --age 7d # Remove all blobs, referenced or not, older than 7 days (and their manifests?) $ ollama prune --age 7d --all # Remove all unreferenced blobs immediately $ ollama prune --age 0 --all # Remove all blobs $ ollama prune --age 0 --all This should provide a safer and more predictable cleanup process. --- server/internal/registry/server.go | 9 ++++++++- server/routes.go | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/server/internal/registry/server.go b/server/internal/registry/server.go index 81085357d..4d44aa8d0 100644 --- a/server/internal/registry/server.go +++ b/server/internal/registry/server.go @@ -31,6 +31,10 @@ type Local struct { // Fallback, if set, is used to handle requests that are not handled by // this handler. Fallback http.Handler + + // Prune, if set, is called to prune the local disk cache after a model + // is deleted. + Prune func() error // optional } // serverError is like ollama.Error, but with a Status field for the HTTP @@ -204,7 +208,10 @@ func (s *Local) handleDelete(_ http.ResponseWriter, r *http.Request) error { if !ok { return &serverError{404, "not_found", "model not found"} } - return nil + if s.Prune == nil { + return nil + } + return s.Prune() } func decodeUserJSON[T any](r io.Reader) (T, error) { diff --git a/server/routes.go b/server/routes.go index 519f04738..f1afad6e0 100644 --- a/server/routes.go +++ b/server/routes.go @@ -1199,6 +1199,8 @@ func (s *Server) GenerateRoutes(rc *ollama.Registry) (http.Handler, error) { Client: rc, Logger: slog.Default(), // TODO(bmizerany): Take a logger, do not use slog.Default() Fallback: r, + + Prune: PruneLayers, } return rs, nil