Skip to content

Commit

Permalink
Merge pull request #1129 from Ace-Tang/gc_exec
Browse files Browse the repository at this point in the history
feature: gc unused exec processes
  • Loading branch information
allencloud authored Apr 18, 2018
2 parents 54eed7d + 9fb027e commit 5caea36
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 0 deletions.
31 changes: 31 additions & 0 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ func NewContainerManager(ctx context.Context, store *meta.Store, cli ctrd.APICli
mgr.Client.SetExitHooks(mgr.exitedAndRelease)
mgr.Client.SetExecExitHooks(mgr.execExitedAndRelease)

go mgr.execProcessGC()

return mgr, mgr.Restore(ctx)
}

Expand Down Expand Up @@ -1742,3 +1744,32 @@ func (mgr *ContainerManager) setBaseFS(ctx context.Context, meta *ContainerMeta,
// io.containerd.runtime.v1.linux as a const used by runc
meta.BaseFS = filepath.Join(mgr.Config.HomeDir, "containerd/state", "io.containerd.runtime.v1.linux", namespaces.Default, info.Name, "rootfs")
}

// execProcessGC cleans unused exec processes config every 5 minutes.
func (mgr *ContainerManager) execProcessGC() {
for range time.Tick(time.Duration(GCExecProcessTick) * time.Minute) {
execProcesses := mgr.ExecProcesses.Values()
cleaned := 0

for id, v := range execProcesses {
execConfig, ok := v.(*ContainerExecConfig)
if !ok {
logrus.Warnf("get incorrect exec config: %v", v)
continue
}
// if unused exec processes are found, we will tag them, and clean
// them in next loop, so that we can ensure exec process can get
// correct exit code.
if execConfig.WaitForClean {
cleaned++
mgr.ExecProcesses.Remove(id)
} else if !execConfig.Running {
execConfig.WaitForClean = true
}
}

if cleaned > 0 {
logrus.Debugf("clean %d unused exec process", cleaned)
}
}
}
9 changes: 9 additions & 0 deletions daemon/mgr/container_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ import (
"github.com/opencontainers/image-spec/specs-go/v1"
)

var (
// GCExecProcessTick is the time interval to trigger gc unused exec config,
// time unit is minute.
GCExecProcessTick = 5
)

const (
// DefaultStopTimeout is the timeout (in seconds) for the syscall signal used to stop a container.
DefaultStopTimeout = 10
Expand Down Expand Up @@ -43,6 +49,9 @@ type ContainerExecConfig struct {

// Error represents the exec process response error.
Error error

// WaitForClean means exec process can be removed.
WaitForClean bool
}

// AttachConfig wraps some infos of attaching.
Expand Down
18 changes: 18 additions & 0 deletions pkg/collect/safe_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,28 @@ func (m *SafeMap) Get(k string) *Value {
return &Value{v, ok}
}

// Values returns all key-values stored in map
func (m *SafeMap) Values() map[string]interface{} {
m.RLock()
defer m.RUnlock()

nmap := make(map[string]interface{})
for k, v := range m.inner {
nmap[k] = v
}

return nmap
}

// Put stores a key-value pair into inner map safely.
func (m *SafeMap) Put(k string, v interface{}) {
m.Lock()
defer m.Unlock()

if m.inner == nil {
return
}

m.inner[k] = v
}

Expand Down
21 changes: 21 additions & 0 deletions pkg/collect/safe_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ func TestSafeMapPutAndGet(t *testing.T) {
assert.Equal(t, value.data, []string{"asdfgh", "123344"})
}

// TestSafeMapDirectNew test functions should not panic.
func TestSafeMapDirectNew(t *testing.T) {
assert := assert.New(t)
defer func() {
if err := recover(); err != nil {
t.Fatal(err)
}
}()

sm := &SafeMap{}
// test Put not panic
sm.Put("k", "v")

// test Remove not panic
sm.Remove("k")

// test Values not panic
values := sm.Values()
assert.Equal(values, map[string]interface{}{})
}

func TestSafeMapRemove(t *testing.T) {
safeMap := NewSafeMap()
assert.Equal(t, len(safeMap.inner), 0)
Expand Down

0 comments on commit 5caea36

Please sign in to comment.