Add Store.ContainerSize()

Add a ContainerSize() method, which knows how to compute the sizes of
container, so that our callers don't need to all be updated when we make
changes to how we store them.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2018-05-30 16:31:08 -04:00
parent ce1b85933f
commit 92105b61a8
2 changed files with 99 additions and 0 deletions

View File

@ -43,6 +43,12 @@ func container(flags *mflag.FlagSet, action string, m storage.Store, args []stri
break
}
}
size, err := m.ContainerSize(container.ID)
if err != nil {
fmt.Printf("Size unknown: %v\n", err)
} else {
fmt.Printf("Size: %d\n", size)
}
fmt.Printf("Layer: %s\n", container.LayerID)
for _, name := range container.BigDataNames {
fmt.Printf("Data: %s\n", name)

View File

@ -19,6 +19,7 @@ import (
"github.com/BurntSushi/toml"
drivers "github.com/containers/storage/drivers"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/directory"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/ioutils"
"github.com/containers/storage/pkg/stringid"
@ -371,6 +372,10 @@ type Store interface {
// associated with a container.
SetContainerBigData(id, key string, data []byte) error
// ContainerSize computes the size of the container's layer and ancillary
// data. Warning: this is a potentially expensive operation.
ContainerSize(id string) (int64, error)
// Layer returns a specific layer.
Layer(id string) (*Layer, error)
@ -1479,6 +1484,94 @@ func (s *store) ImageSize(id string) (int64, error) {
return size, nil
}
func (s *store) ContainerSize(id string) (int64, error) {
lstore, err := s.LayerStore()
if err != nil {
return -1, err
}
lstores, err := s.ROLayerStores()
if err != nil {
return -1, err
}
for _, store := range append([]ROLayerStore{lstore}, lstores...) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
store.Load()
}
}
// Get the location of the container directory and container run directory.
// Do it before we lock the container store because they do, too.
cdir, err := s.ContainerDirectory(id)
if err != nil {
return -1, err
}
rdir, err := s.ContainerRunDirectory(id)
if err != nil {
return -1, err
}
rcstore, err := s.ContainerStore()
if err != nil {
return -1, err
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
rcstore.Load()
}
// Read the container record.
container, err := rcstore.Get(id)
if err != nil {
return -1, err
}
// Read the container's layer's size.
var layer *Layer
var size int64
for _, store := range append([]ROLayerStore{lstore}, lstores...) {
if layer, err = store.Get(container.LayerID); err == nil {
size, err = store.DiffSize("", layer.ID)
if err != nil {
return -1, errors.Wrapf(err, "error determining size of layer with ID %q", layer.ID)
}
break
}
}
if layer == nil {
return -1, errors.Wrapf(ErrLayerUnknown, "error locating layer with ID %q", container.LayerID)
}
// Count big data items.
names, err := rcstore.BigDataNames(id)
if err != nil {
return -1, errors.Wrapf(err, "error reading list of big data items for container %q", container.ID)
}
for _, name := range names {
n, err := rcstore.BigDataSize(id, name)
if err != nil {
return -1, errors.Wrapf(err, "error reading size of big data item %q for container %q", name, id)
}
size += n
}
// Count the size of our container directory and container run directory.
n, err := directory.Size(cdir)
if err != nil {
return -1, err
}
size += n
n, err = directory.Size(rdir)
if err != nil {
return -1, err
}
size += n
return size, nil
}
func (s *store) ListContainerBigData(id string) ([]string, error) {
rcstore, err := s.ContainerStore()
if err != nil {