github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/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(id ID) error { 65 img, err := is.Get(id) 66 if err != nil { 67 logrus.Errorf("invalid image %v, %v", id, 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(digest.Digest(id)); err != nil { 78 return err 79 } 80 81 imageMeta := &imageMeta{ 82 layer: l, 83 children: make(map[ID]struct{}), 84 } 85 86 is.images[ID(id)] = 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 := ID(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(digest.Digest(imageID)); 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 return "", err 174 } 175 return ID(dgst), nil 176 } 177 178 func (is *store) Get(id ID) (*Image, error) { 179 // todo: Check if image is in images 180 // todo: Detect manual insertions and start using them 181 config, err := is.fs.Get(id) 182 if err != nil { 183 return nil, err 184 } 185 186 img, err := NewFromJSON(config) 187 if err != nil { 188 return nil, err 189 } 190 img.computedID = id 191 192 img.Parent, err = is.GetParent(id) 193 if err != nil { 194 img.Parent = "" 195 } 196 197 return img, nil 198 } 199 200 func (is *store) Delete(id ID) ([]layer.Metadata, error) { 201 is.Lock() 202 defer is.Unlock() 203 204 imageMeta := is.images[id] 205 if imageMeta == nil { 206 return nil, fmt.Errorf("unrecognized image ID %s", id.String()) 207 } 208 for id := range imageMeta.children { 209 is.fs.DeleteMetadata(id, "parent") 210 } 211 if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil { 212 delete(is.images[parent].children, id) 213 } 214 215 if err := is.digestSet.Remove(digest.Digest(id)); err != nil { 216 logrus.Errorf("error removing %s from digest set: %q", id, err) 217 } 218 delete(is.images, id) 219 is.fs.Delete(id) 220 221 if imageMeta.layer != nil { 222 return is.ls.Release(imageMeta.layer) 223 } 224 return nil, nil 225 } 226 227 func (is *store) SetParent(id, parent ID) error { 228 is.Lock() 229 defer is.Unlock() 230 parentMeta := is.images[parent] 231 if parentMeta == nil { 232 return fmt.Errorf("unknown parent image ID %s", parent.String()) 233 } 234 parentMeta.children[id] = struct{}{} 235 return is.fs.SetMetadata(id, "parent", []byte(parent)) 236 } 237 238 func (is *store) GetParent(id ID) (ID, error) { 239 d, err := is.fs.GetMetadata(id, "parent") 240 if err != nil { 241 return "", err 242 } 243 return ID(d), nil // todo: validate? 244 } 245 246 func (is *store) Children(id ID) []ID { 247 is.Lock() 248 defer is.Unlock() 249 250 return is.children(id) 251 } 252 253 func (is *store) children(id ID) []ID { 254 var ids []ID 255 if is.images[id] != nil { 256 for id := range is.images[id].children { 257 ids = append(ids, id) 258 } 259 } 260 return ids 261 } 262 263 func (is *store) Heads() map[ID]*Image { 264 return is.imagesMap(false) 265 } 266 267 func (is *store) Map() map[ID]*Image { 268 return is.imagesMap(true) 269 } 270 271 func (is *store) imagesMap(all bool) map[ID]*Image { 272 is.Lock() 273 defer is.Unlock() 274 275 images := make(map[ID]*Image) 276 277 for id := range is.images { 278 if !all && len(is.children(id)) > 0 { 279 continue 280 } 281 img, err := is.Get(id) 282 if err != nil { 283 logrus.Errorf("invalid image access: %q, error: %q", id, err) 284 continue 285 } 286 images[id] = img 287 } 288 return images 289 }