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