1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

layer: optimize layerStore mountL

Goroutine stack analisys shown some lock contention
while doing massively (100 instances of `docker rm`)
parallel image removal, with many goroutines waiting
for the mountL mutex. Optimize it.

With this commit, the above operation is about 3x
faster, with no noticeable change to container
creation times (tested on aufs and overlay2).

kolyshkin@:
- squashed commits
- added description
- protected CreateRWLayer against name collisions by
temporary assiging nil to ls.mounts[name], and treating
nil as "non-existent" in all the other functions.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 05250a4f00)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Xinfeng Liu 2019-04-23 02:33:20 +00:00 committed by Sebastiaan van Stijn
parent 80a35e0bd4
commit eaa3e69d14
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
2 changed files with 35 additions and 21 deletions

View file

@ -189,7 +189,9 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) {
} }
func (ls *layerStore) loadMount(mount string) error { func (ls *layerStore) loadMount(mount string) error {
if _, ok := ls.mounts[mount]; ok { ls.mountL.Lock()
defer ls.mountL.Unlock()
if m := ls.mounts[mount]; m != nil {
return nil return nil
} }
@ -477,7 +479,7 @@ func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
return ls.releaseLayer(layer) return ls.releaseLayer(layer)
} }
func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error) { func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWLayerOpts) (_ RWLayer, err error) {
var ( var (
storageOpt map[string]string storageOpt map[string]string
initFunc MountInit initFunc MountInit
@ -491,13 +493,21 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
} }
ls.mountL.Lock() ls.mountL.Lock()
defer ls.mountL.Unlock() if _, ok := ls.mounts[name]; ok {
m, ok := ls.mounts[name] ls.mountL.Unlock()
if ok {
return nil, ErrMountNameConflict return nil, ErrMountNameConflict
} }
// Avoid name collision by temporary assigning nil
ls.mounts[name] = nil
ls.mountL.Unlock()
defer func() {
if err != nil {
ls.mountL.Lock()
delete(ls.mounts, name)
ls.mountL.Unlock()
}
}()
var err error
var pid string var pid string
var p *roLayer var p *roLayer
if string(parent) != "" { if string(parent) != "" {
@ -517,7 +527,7 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
}() }()
} }
m = &mountedLayer{ m := &mountedLayer{
name: name, name: name,
parent: p, parent: p,
mountID: ls.mountID(name), mountID: ls.mountID(name),
@ -528,7 +538,7 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
if initFunc != nil { if initFunc != nil {
pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc, storageOpt) pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc, storageOpt)
if err != nil { if err != nil {
return nil, err return
} }
m.initID = pid m.initID = pid
} }
@ -538,10 +548,10 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
} }
if err = ls.driver.CreateReadWrite(m.mountID, pid, createOpts); err != nil { if err = ls.driver.CreateReadWrite(m.mountID, pid, createOpts); err != nil {
return nil, err return
} }
if err = ls.saveMount(m); err != nil { if err = ls.saveMount(m); err != nil {
return nil, err return
} }
return m.getReference(), nil return m.getReference(), nil
@ -549,9 +559,9 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
func (ls *layerStore) GetRWLayer(id string) (RWLayer, error) { func (ls *layerStore) GetRWLayer(id string) (RWLayer, error) {
ls.mountL.Lock() ls.mountL.Lock()
defer ls.mountL.Unlock() mount := ls.mounts[id]
mount, ok := ls.mounts[id] ls.mountL.Unlock()
if !ok { if mount == nil {
return nil, ErrMountDoesNotExist return nil, ErrMountDoesNotExist
} }
@ -561,8 +571,8 @@ func (ls *layerStore) GetRWLayer(id string) (RWLayer, error) {
func (ls *layerStore) GetMountID(id string) (string, error) { func (ls *layerStore) GetMountID(id string) (string, error) {
ls.mountL.Lock() ls.mountL.Lock()
defer ls.mountL.Unlock() defer ls.mountL.Unlock()
mount, ok := ls.mounts[id] mount := ls.mounts[id]
if !ok { if mount == nil {
return "", ErrMountDoesNotExist return "", ErrMountDoesNotExist
} }
logrus.Debugf("GetMountID id: %s -> mountID: %s", id, mount.mountID) logrus.Debugf("GetMountID id: %s -> mountID: %s", id, mount.mountID)
@ -572,9 +582,9 @@ func (ls *layerStore) GetMountID(id string) (string, error) {
func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) { func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
ls.mountL.Lock() ls.mountL.Lock()
defer ls.mountL.Unlock() m := ls.mounts[l.Name()]
m, ok := ls.mounts[l.Name()] ls.mountL.Unlock()
if !ok { if m == nil {
return []Metadata{}, nil return []Metadata{}, nil
} }
@ -606,7 +616,9 @@ func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
return nil, err return nil, err
} }
ls.mountL.Lock()
delete(ls.mounts, m.Name()) delete(ls.mounts, m.Name())
ls.mountL.Unlock()
ls.layerL.Lock() ls.layerL.Lock()
defer ls.layerL.Unlock() defer ls.layerL.Unlock()
@ -634,7 +646,9 @@ func (ls *layerStore) saveMount(mount *mountedLayer) error {
} }
} }
ls.mountL.Lock()
ls.mounts[mount.name] = mount ls.mounts[mount.name] = mount
ls.mountL.Unlock()
return nil return nil
} }

View file

@ -18,9 +18,9 @@ import (
// after migration the layer may be retrieved by the given name. // after migration the layer may be retrieved by the given name.
func (ls *layerStore) CreateRWLayerByGraphID(name, graphID string, parent ChainID) (err error) { func (ls *layerStore) CreateRWLayerByGraphID(name, graphID string, parent ChainID) (err error) {
ls.mountL.Lock() ls.mountL.Lock()
defer ls.mountL.Unlock() m := ls.mounts[name]
m, ok := ls.mounts[name] ls.mountL.Unlock()
if ok { if m != nil {
if m.parent.chainID != parent { if m.parent.chainID != parent {
return errors.New("name conflict, mismatched parent") return errors.New("name conflict, mismatched parent")
} }