Skip to content

Commit

Permalink
Add image layer storage usage (#8430)
Browse files Browse the repository at this point in the history
The current implementation of image storage usage always use
vCenter datastore file browser to get all layers of images
and sum the related vmdk file sizes. In some vsphere environments,
the browser response is very slow with 30+ seconds with
only 10 layers.

This fix changes to accumulate storage usage when a layer is added
or deleted from datastore, and keep the latest usage value into cache.
  • Loading branch information
wjun authored Dec 26, 2018
1 parent 019404c commit 6b4310f
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 8 deletions.
16 changes: 11 additions & 5 deletions lib/apiservers/portlayer/restapi/handlers/storage_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -738,13 +738,19 @@ func (h *StorageHandlersImpl) GetImageStorageUsage(params storage.GetImageStorag
op := trace.NewOperationFromID(context.Background(), params.OpID, "GetImageStorageUsage(%s)", params.StoreName)
defer trace.End(trace.Begin("GetImageStorageUsage", op))

result, err := h.imageCache.DataStore.GetImageStorageUsage(op, params.StoreName)
if err != nil {
op.Errorf("Error gettting image storage usage: %s", err)
return storage.NewGetImageStorageUsageDefault(500)
cachedResult := h.imageCache.ImageStorageUsage()
// If cache is not set, read it from datastore
if cachedResult < 0 {
result, err := h.imageCache.DataStore.GetImageStorageUsage(op, params.StoreName)
if err != nil {
op.Errorf("Error getting image storage usage from datastore: %s", err)
return storage.NewGetImageStorageUsageDefault(500)
}
h.imageCache.SetImageStorageUsage(result)
cachedResult = result
}

return storage.NewGetImageStorageUsageOK().WithPayload(result)
return storage.NewGetImageStorageUsageOK().WithPayload(cachedResult)
}

//utility functions
Expand Down
62 changes: 60 additions & 2 deletions lib/portlayer/storage/image/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,16 @@ type NameLookupCache struct {

// The image store implementation. This mutates the actual disk images.
DataStore image.ImageStorer

// Track image layers storage usage
imageStorageUsage int64
}

func NewLookupCache(ds image.ImageStorer) *NameLookupCache {
return &NameLookupCache{
DataStore: ds,
storeCache: make(map[url.URL]*index.Index),
DataStore: ds,
storeCache: make(map[url.URL]*index.Index),
imageStorageUsage: -1,
}
}

Expand Down Expand Up @@ -265,6 +269,10 @@ func (c *NameLookupCache) WriteImage(op trace.Operation, parent *image.Image, ID
return nil, err
}

if err = c.UpdateStorageUsage(op, i.Store, i.ID); err != nil {
return nil, err
}

c.storeCacheLock.Lock()
indx := c.storeCache[*parent.Store]
c.storeCacheLock.Unlock()
Expand All @@ -277,6 +285,25 @@ func (c *NameLookupCache) WriteImage(op trace.Operation, parent *image.Image, ID
return i, nil
}

func (c *NameLookupCache) UpdateStorageUsage(op trace.Operation, store *url.URL, id string) error {
storeName, err := util.ImageStoreName(store)
if err != nil {
return err
}
size, err := c.DataStore.GetImageLayerStorageUsage(op, storeName, id)
if err != nil {
op.Errorf("Get image layer size of %s failed with: %s", id, err)
// size is 0 and continue
}

if size > 0 {
c.storeCacheLock.Lock()
c.imageStorageUsage += size
c.storeCacheLock.Unlock()
}
return nil
}

func (c *NameLookupCache) Export(op trace.Operation, store *url.URL, id, ancestor string, spec *archive.FilterSpec, data bool) (io.ReadCloser, error) {
return c.DataStore.Export(op, id, ancestor, spec, data)
}
Expand Down Expand Up @@ -424,12 +451,31 @@ func (c *NameLookupCache) DeleteImage(op trace.Operation, img *image.Image) (*im
return nil, &image.ErrImageInUse{Msg: img.Self() + " in use by child images"}
}

// Get image layer storage usage
storeName, err := util.ImageStoreName(img.Store)
if err != nil {
return nil, err
}

size, err := c.DataStore.GetImageLayerStorageUsage(op, storeName, img.ID)
if err != nil {
op.Errorf("Get image layer size of %s failed with: %s", img.ID, err)
// size is 0 and continue
}

// The datastore will tell us if the image is attached
if _, err = c.DataStore.DeleteImage(op, img); err != nil {
op.Errorf("%s", err)
return nil, err
}

// update image storage usage
if size > 0 {
c.storeCacheLock.Lock()
c.imageStorageUsage -= size
c.storeCacheLock.Unlock()
}

// Remove the image from the cache
if _, err = indx.Delete(img.Self()); err != nil {
op.Errorf("%s", err)
Expand Down Expand Up @@ -507,3 +553,15 @@ func (c *NameLookupCache) DeleteBranch(op trace.Operation, img *image.Image, kee

return deletedImages, nil
}

func (c *NameLookupCache) ImageStorageUsage() int64 {
c.storeCacheLock.Lock()
defer c.storeCacheLock.Unlock()
return c.imageStorageUsage
}

func (c *NameLookupCache) SetImageStorageUsage(value int64) {
c.storeCacheLock.Lock()
defer c.storeCacheLock.Unlock()
c.imageStorageUsage = value
}
3 changes: 3 additions & 0 deletions lib/portlayer/storage/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ type ImageStorer interface {
// GetImageStorageUsage gets the image storage usage from the image store.
GetImageStorageUsage(op trace.Operation, storeName string) (int64, error)

// GetImageLayerStorageUsage gets the image layer storage usage from the image store.
GetImageLayerStorageUsage(op trace.Operation, storeName, ID string) (int64, error)

storage.Resolver
storage.Importer
storage.Exporter
Expand Down
4 changes: 4 additions & 0 deletions lib/portlayer/storage/image/mock/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,7 @@ func (c *MockDataStore) DeleteImage(op trace.Operation, image *image.Image) (*im
func (c *MockDataStore) GetImageStorageUsage(op trace.Operation, storeName string) (int64, error) {
return 0, nil
}

func (c *MockDataStore) GetImageLayerStorageUsage(op trace.Operation, storeName, ID string) (int64, error) {
return 0, nil
}
6 changes: 5 additions & 1 deletion lib/portlayer/storage/image/vsphere/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (v *ImageStore) imageStorePath(storeName string) string {

// Returns the path to the image relative to the given
// store. The dir structure for an image in the datastore is
// `/VIC/imageStoreName (currently the vch uuid)/imageName/imageName.vmkd`
// `/VIC/imageStoreName (currently the vch uuid)/imageName/imageName.vmdk`
func (v *ImageStore) imageDirPath(storeName, imageName string) string {
return path.Join(v.imageStorePath(storeName), imageName)
}
Expand Down Expand Up @@ -594,6 +594,10 @@ func (v *ImageStore) GetImageStorageUsage(op trace.Operation, storeName string)
return v.Helper.GetFilesSize(op, v.imageStorePath(storeName), true, "*.vmdk")
}

func (v *ImageStore) GetImageLayerStorageUsage(op trace.Operation, storeName, ID string) (int64, error) {
return v.Helper.GetFilesSize(op, v.imageDirPath(storeName, ID), true, "*.vmdk")
}

// DeleteImage deletes an image from the image store. If the image is in
// use either by way of inheritance or because it's attached to a
// container, this will return an error.
Expand Down

0 comments on commit 6b4310f

Please sign in to comment.