mirror of
				https://github.com/containers/podman.git
				synced 2025-10-31 18:08:51 +08:00 
			
		
		
		
	 8827100b98
			
		
	
	8827100b98
	
	
	
		
			
			Listing images has shown increasing performance penalties with an increasing number of images. Unless `--all` is specified, Podman will filter intermediate images. Determining intermediate images has been done by finding (and comparing!) parent images which is expensive. We had to query the storage many times which turned it into a bottleneck. Instead, create a layer tree and assign one or more images to nodes that match the images' top layer. Determining the children of an image is now exponentially faster as we already know the child images from the layer graph and the images using the same top layer, which may also be considered child images based on their history. On my system with 510 images, a rootful image list drops from 6 secs down to 0.3 secs. Also use the tree to compute parent nodes, and to filter intermediate images for pruning. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
		
			
				
	
	
		
			119 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package utils
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/containers/image/v5/docker"
 | |
| 	"github.com/containers/image/v5/storage"
 | |
| 	"github.com/containers/image/v5/transports/alltransports"
 | |
| 	"github.com/containers/image/v5/types"
 | |
| 	"github.com/containers/podman/v2/libpod"
 | |
| 	"github.com/containers/podman/v2/libpod/image"
 | |
| 	"github.com/gorilla/schema"
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| // ParseDockerReference parses the specified image name to a
 | |
| // `types.ImageReference` and enforces it to refer to a docker-transport
 | |
| // reference.
 | |
| func ParseDockerReference(name string) (types.ImageReference, error) {
 | |
| 	dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
 | |
| 	imageRef, err := alltransports.ParseImageName(name)
 | |
| 	if err == nil && imageRef.Transport().Name() != docker.Transport.Name() {
 | |
| 		return nil, errors.Errorf("reference %q must be a docker reference", name)
 | |
| 	} else if err != nil {
 | |
| 		origErr := err
 | |
| 		imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, name))
 | |
| 		if err != nil {
 | |
| 			return nil, errors.Wrapf(origErr, "reference %q must be a docker reference", name)
 | |
| 		}
 | |
| 	}
 | |
| 	return imageRef, nil
 | |
| }
 | |
| 
 | |
| // ParseStorageReference parses the specified image name to a
 | |
| // `types.ImageReference` and enforces it to refer to a
 | |
| // containers-storage-transport reference.
 | |
| func ParseStorageReference(name string) (types.ImageReference, error) {
 | |
| 	storagePrefix := fmt.Sprintf("%s:", storage.Transport.Name())
 | |
| 	imageRef, err := alltransports.ParseImageName(name)
 | |
| 	if err == nil && imageRef.Transport().Name() != docker.Transport.Name() {
 | |
| 		return nil, errors.Errorf("reference %q must be a storage reference", name)
 | |
| 	} else if err != nil {
 | |
| 		origErr := err
 | |
| 		imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", storagePrefix, name))
 | |
| 		if err != nil {
 | |
| 			return nil, errors.Wrapf(origErr, "reference %q must be a storage reference", name)
 | |
| 		}
 | |
| 	}
 | |
| 	return imageRef, nil
 | |
| }
 | |
| 
 | |
| // GetImages is a common function used to get images for libpod and other compatibility
 | |
| // mechanisms
 | |
| func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
 | |
| 	decoder := r.Context().Value("decoder").(*schema.Decoder)
 | |
| 	runtime := r.Context().Value("runtime").(*libpod.Runtime)
 | |
| 	query := struct {
 | |
| 		All     bool
 | |
| 		Filters map[string][]string `schema:"filters"`
 | |
| 		Digests bool
 | |
| 		Filter  string // Docker 1.24 compatibility
 | |
| 	}{
 | |
| 		// This is where you can override the golang default value for one of fields
 | |
| 	}
 | |
| 
 | |
| 	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	var filters = []string{}
 | |
| 	if _, found := r.URL.Query()["digests"]; found && query.Digests {
 | |
| 		UnSupportedParameter("digests")
 | |
| 	}
 | |
| 	var (
 | |
| 		images []*image.Image
 | |
| 		err    error
 | |
| 	)
 | |
| 
 | |
| 	queryFilters := query.Filters
 | |
| 	if !IsLibpodRequest(r) && len(query.Filter) > 0 { // Docker 1.24 compatibility
 | |
| 		if queryFilters == nil {
 | |
| 			queryFilters = make(map[string][]string)
 | |
| 		}
 | |
| 		queryFilters["reference"] = append(queryFilters["reference"], query.Filter)
 | |
| 	}
 | |
| 
 | |
| 	if len(queryFilters) > 0 {
 | |
| 		for k, v := range queryFilters {
 | |
| 			filters = append(filters, fmt.Sprintf("%s=%s", k, strings.Join(v, "=")))
 | |
| 		}
 | |
| 		images, err = runtime.ImageRuntime().GetImagesWithFilters(filters)
 | |
| 		if err != nil {
 | |
| 			return images, err
 | |
| 		}
 | |
| 	} else {
 | |
| 		images, err = runtime.ImageRuntime().GetImages()
 | |
| 		if err != nil {
 | |
| 			return images, err
 | |
| 		}
 | |
| 	}
 | |
| 	if query.All {
 | |
| 		return images, nil
 | |
| 	}
 | |
| 
 | |
| 	filter, err := runtime.ImageRuntime().IntermediateFilter(r.Context(), images)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	images = image.FilterImages(images, []image.ResultFilter{filter})
 | |
| 
 | |
| 	return images, nil
 | |
| }
 | |
| 
 | |
| func GetImage(r *http.Request, name string) (*image.Image, error) {
 | |
| 	runtime := r.Context().Value("runtime").(*libpod.Runtime)
 | |
| 	return runtime.ImageRuntime().NewFromLocal(name)
 | |
| }
 |