github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/image/store.go (about)

     1  package image
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"sync"
     8  
     9  	"github.com/Sirupsen/logrus"
    10  	"github.com/docker/distribution/digest"
    11  	"github.com/docker/docker/layer"
    12  )
    13  
    14  // Store is an interface for creating and accessing images
    15  type Store interface {
    16  	Create(config []byte) (ID, error)
    17  	Get(id ID) (*Image, error)
    18  	Delete(id ID) ([]layer.Metadata, error)
    19  	Search(partialID string) (ID, error)
    20  	SetParent(id ID, parent ID) error
    21  	GetParent(id ID) (ID, error)
    22  	Children(id ID) []ID
    23  	Map() map[ID]*Image
    24  	Heads() map[ID]*Image
    25  }
    26  
    27  // LayerGetReleaser is a minimal interface for getting and releasing images.
    28  type LayerGetReleaser interface {
    29  	Get(layer.ChainID) (layer.Layer, error)
    30  	Release(layer.Layer) ([]layer.Metadata, error)
    31  }
    32  
    33  type imageMeta struct {
    34  	layer    layer.Layer
    35  	children map[ID]struct{}
    36  }
    37  
    38  type store struct {
    39  	sync.Mutex
    40  	ls        LayerGetReleaser
    41  	images    map[ID]*imageMeta
    42  	fs        StoreBackend
    43  	digestSet *digest.Set
    44  }
    45  
    46  // NewImageStore returns new store object for given layer store
    47  func NewImageStore(fs StoreBackend, ls LayerGetReleaser) (Store, error) {
    48  	is := &store{
    49  		ls:        ls,
    50  		images:    make(map[ID]*imageMeta),
    51  		fs:        fs,
    52  		digestSet: digest.NewSet(),
    53  	}
    54  
    55  	// load all current images and retain layers
    56  	if err := is.restore(); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	return is, nil
    61  }
    62  
    63  func (is *store) restore() error {
    64  	err := is.fs.Walk(func(dgst digest.Digest) error {
    65  		img, err := is.Get(IDFromDigest(dgst))
    66  		if err != nil {
    67  			logrus.Errorf("invalid image %v, %v", dgst, err)
    68  			return nil
    69  		}
    70  		var l layer.Layer
    71  		if chainID := img.RootFS.ChainID(); chainID != "" {
    72  			l, err = is.ls.Get(chainID)
    73  			if err != nil {
    74  				return err
    75  			}
    76  		}
    77  		if err := is.digestSet.Add(dgst); err != nil {
    78  			return err
    79  		}
    80  
    81  		imageMeta := &imageMeta{
    82  			layer:    l,
    83  			children: make(map[ID]struct{}),
    84  		}
    85  
    86  		is.images[IDFromDigest(dgst)] = imageMeta
    87  
    88  		return nil
    89  	})
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	// Second pass to fill in children maps
    95  	for id := range is.images {
    96  		if parent, err := is.GetParent(id); err == nil {
    97  			if parentMeta := is.images[parent]; parentMeta != nil {
    98  				parentMeta.children[id] = struct{}{}
    99  			}
   100  		}
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  func (is *store) Create(config []byte) (ID, error) {
   107  	var img Image
   108  	err := json.Unmarshal(config, &img)
   109  	if err != nil {
   110  		return "", err
   111  	}
   112  
   113  	// Must reject any config that references diffIDs from the history
   114  	// which aren't among the rootfs layers.
   115  	rootFSLayers := make(map[layer.DiffID]struct{})
   116  	for _, diffID := range img.RootFS.DiffIDs {
   117  		rootFSLayers[diffID] = struct{}{}
   118  	}
   119  
   120  	layerCounter := 0
   121  	for _, h := range img.History {
   122  		if !h.EmptyLayer {
   123  			layerCounter++
   124  		}
   125  	}
   126  	if layerCounter > len(img.RootFS.DiffIDs) {
   127  		return "", errors.New("too many non-empty layers in History section")
   128  	}
   129  
   130  	dgst, err := is.fs.Set(config)
   131  	if err != nil {
   132  		return "", err
   133  	}
   134  	imageID := IDFromDigest(dgst)
   135  
   136  	is.Lock()
   137  	defer is.Unlock()
   138  
   139  	if _, exists := is.images[imageID]; exists {
   140  		return imageID, nil
   141  	}
   142  
   143  	layerID := img.RootFS.ChainID()
   144  
   145  	var l layer.Layer
   146  	if layerID != "" {
   147  		l, err = is.ls.Get(layerID)
   148  		if err != nil {
   149  			return "", err
   150  		}
   151  	}
   152  
   153  	imageMeta := &imageMeta{
   154  		layer:    l,
   155  		children: make(map[ID]struct{}),
   156  	}
   157  
   158  	is.images[imageID] = imageMeta
   159  	if err := is.digestSet.Add(imageID.Digest()); err != nil {
   160  		delete(is.images, imageID)
   161  		return "", err
   162  	}
   163  
   164  	return imageID, nil
   165  }
   166  
   167  func (is *store) Search(term string) (ID, error) {
   168  	is.Lock()
   169  	defer is.Unlock()
   170  
   171  	dgst, err := is.digestSet.Lookup(term)
   172  	if err != nil {
   173  		if err == digest.ErrDigestNotFound {
   174  			err = fmt.Errorf("No such image: %s", term)
   175  		}
   176  		return "", err
   177  	}
   178  	return IDFromDigest(dgst), nil
   179  }
   180  
   181  func (is *store) Get(id ID) (*Image, error) {
   182  	// todo: Check if image is in images
   183  	// todo: Detect manual insertions and start using them
   184      fmt.Println("image/store.go Get()")
   185  
   186      config, err := is.fs.Get(id.Digest())
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  
   191      //fmt.Println("image/store.go Get() %v", config)
   192  
   193  	img, err := NewFromJSON(config)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	img.computedID = id
   198  
   199  	img.Parent, err = is.GetParent(id)
   200  	if err != nil {
   201  		img.Parent = ""
   202  	}
   203  
   204  	return img, nil
   205  }
   206  
   207  func (is *store) Delete(id ID) ([]layer.Metadata, error) {
   208  	is.Lock()
   209  	defer is.Unlock()
   210  
   211  	imageMeta := is.images[id]
   212  	if imageMeta == nil {
   213  		return nil, fmt.Errorf("unrecognized image ID %s", id.String())
   214  	}
   215  	for id := range imageMeta.children {
   216  		is.fs.DeleteMetadata(id.Digest(), "parent")
   217  	}
   218  	if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
   219  		delete(is.images[parent].children, id)
   220  	}
   221  
   222  	if err := is.digestSet.Remove(id.Digest()); err != nil {
   223  		logrus.Errorf("error removing %s from digest set: %q", id, err)
   224  	}
   225  	delete(is.images, id)
   226  	is.fs.Delete(id.Digest())
   227  
   228  	if imageMeta.layer != nil {
   229  		return is.ls.Release(imageMeta.layer)
   230  	}
   231  	return nil, nil
   232  }
   233  
   234  func (is *store) SetParent(id, parent ID) error {
   235  	is.Lock()
   236  	defer is.Unlock()
   237  	parentMeta := is.images[parent]
   238  	if parentMeta == nil {
   239  		return fmt.Errorf("unknown parent image ID %s", parent.String())
   240  	}
   241  	if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
   242  		delete(is.images[parent].children, id)
   243  	}
   244  	parentMeta.children[id] = struct{}{}
   245  	return is.fs.SetMetadata(id.Digest(), "parent", []byte(parent))
   246  }
   247  
   248  func (is *store) GetParent(id ID) (ID, error) {
   249  	d, err := is.fs.GetMetadata(id.Digest(), "parent")
   250  	if err != nil {
   251  		return "", err
   252  	}
   253  	return ID(d), nil // todo: validate?
   254  }
   255  
   256  func (is *store) Children(id ID) []ID {
   257  	is.Lock()
   258  	defer is.Unlock()
   259  
   260  	return is.children(id)
   261  }
   262  
   263  func (is *store) children(id ID) []ID {
   264  	var ids []ID
   265  	if is.images[id] != nil {
   266  		for id := range is.images[id].children {
   267  			ids = append(ids, id)
   268  		}
   269  	}
   270  	return ids
   271  }
   272  
   273  func (is *store) Heads() map[ID]*Image {
   274  	return is.imagesMap(false)
   275  }
   276  
   277  func (is *store) Map() map[ID]*Image {
   278  	return is.imagesMap(true)
   279  }
   280  
   281  func (is *store) imagesMap(all bool) map[ID]*Image {
   282  	is.Lock()
   283  	defer is.Unlock()
   284  
   285  	images := make(map[ID]*Image)
   286  
   287  	for id := range is.images {
   288  		if !all && len(is.children(id)) > 0 {
   289  			continue
   290  		}
   291  		img, err := is.Get(id)
   292  		if err != nil {
   293  			logrus.Errorf("invalid image access: %q, error: %q", id, err)
   294  			continue
   295  		}
   296  		images[id] = img
   297  	}
   298  	return images
   299  }