From a937a6831763ec0c7e214c3408d29ca7be9078ca Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Mon, 12 Jan 2026 13:17:48 -0800 Subject: [PATCH] server: fix slow 'ollama rm' of models with many layers (#13680) RemoveLayers was calling Manifests() for each layer to check if it was shared with other models. For models with many blobs (e.g., tensor models), this caused O(N*M) manifest reads. Now loads manifests once and builds a set of in-use digests. --- server/manifest.go | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/server/manifest.go b/server/manifest.go index 0d348dd06..da596f658 100644 --- a/server/manifest.go +++ b/server/manifest.go @@ -47,16 +47,40 @@ func (m *Manifest) Remove() error { } func (m *Manifest) RemoveLayers() error { - for _, layer := range append(m.Layers, m.Config) { - if layer.Digest != "" { - if err := layer.Remove(); errors.Is(err, os.ErrNotExist) { - slog.Debug("layer does not exist", "digest", layer.Digest) - } else if err != nil { - return err + ms, err := Manifests(true) + if err != nil { + return err + } + + // Build set of digests still in use by other manifests + inUse := make(map[string]struct{}) + for _, other := range ms { + for _, layer := range append(other.Layers, other.Config) { + if layer.Digest != "" { + inUse[layer.Digest] = struct{}{} } } } + // Remove layers not used by any other manifest + for _, layer := range append(m.Layers, m.Config) { + if layer.Digest == "" { + continue + } + if _, used := inUse[layer.Digest]; used { + continue + } + blob, err := GetBlobsPath(layer.Digest) + if err != nil { + return err + } + if err := os.Remove(blob); errors.Is(err, os.ErrNotExist) { + slog.Debug("layer does not exist", "digest", layer.Digest) + } else if err != nil { + return err + } + } + return nil }