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

Add support to trigger immediate garbage collection

Right now the namespace paths are cleaned up every
garbage collection period. But if the daemon is restarted
before all the namespace paths of removed containers are
garbage collected they will remain there forever. The fix
is to provide a GC() api so that garbage collection can be
triggered immediately.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-06-05 11:46:33 -07:00
parent dbc025117d
commit 15ddc3717a
4 changed files with 64 additions and 5 deletions

View file

@ -59,6 +59,7 @@ import (
"github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/hostdiscovery" "github.com/docker/libnetwork/hostdiscovery"
"github.com/docker/libnetwork/sandbox"
"github.com/docker/libnetwork/types" "github.com/docker/libnetwork/types"
"github.com/docker/swarm/pkg/store" "github.com/docker/swarm/pkg/store"
) )
@ -84,6 +85,9 @@ type NetworkController interface {
// NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned. // NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned.
NetworkByID(id string) (Network, error) NetworkByID(id string) (Network, error)
// GC triggers immediate garbage collection of resources which are garbage collected.
GC()
} }
// NetworkWalker is a client provided function which will be used to walk the Networks. // NetworkWalker is a client provided function which will be used to walk the Networks.
@ -394,3 +398,7 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
} }
return d, nil return d, nil
} }
func (c *controller) GC() {
sandbox.GC()
}

View file

@ -25,6 +25,7 @@ var (
gpmLock sync.Mutex gpmLock sync.Mutex
gpmWg sync.WaitGroup gpmWg sync.WaitGroup
gpmCleanupPeriod = 60 * time.Second gpmCleanupPeriod = 60 * time.Second
gpmChan = make(chan chan struct{})
) )
// The networkNamespace type is the linux implementation of the Sandbox // The networkNamespace type is the linux implementation of the Sandbox
@ -56,7 +57,18 @@ func removeUnusedPaths() {
period := gpmCleanupPeriod period := gpmCleanupPeriod
gpmLock.Unlock() gpmLock.Unlock()
for range time.Tick(period) { ticker := time.NewTicker(period)
for {
var (
gc chan struct{}
gcOk bool
)
select {
case <-ticker.C:
case gc, gcOk = <-gpmChan:
}
gpmLock.Lock() gpmLock.Lock()
pathList := make([]string, 0, len(garbagePathMap)) pathList := make([]string, 0, len(garbagePathMap))
for path := range garbagePathMap { for path := range garbagePathMap {
@ -71,6 +83,9 @@ func removeUnusedPaths() {
} }
gpmWg.Done() gpmWg.Done()
if gcOk {
close(gc)
}
} }
} }
@ -86,6 +101,18 @@ func removeFromGarbagePaths(path string) {
gpmLock.Unlock() gpmLock.Unlock()
} }
// GC triggers garbage collection of namespace path right away
// and waits for it.
func GC() {
waitGC := make(chan struct{})
// Trigger GC now
gpmChan <- waitGC
// wait for gc to complete
<-waitGC
}
// GenerateKey generates a sandbox key based on the passed // GenerateKey generates a sandbox key based on the passed
// container id. // container id.
func GenerateKey(containerID string) string { func GenerateKey(containerID string) string {

View file

@ -153,9 +153,16 @@ func verifySandbox(t *testing.T, s Sandbox) {
} }
} }
func verifyCleanup(t *testing.T, s Sandbox) { func verifyCleanup(t *testing.T, s Sandbox, wait bool) {
time.Sleep(time.Duration(gpmCleanupPeriod * 2)) if wait {
time.Sleep(time.Duration(gpmCleanupPeriod * 2))
}
if _, err := os.Stat(s.Key()); err == nil { if _, err := os.Stat(s.Key()); err == nil {
t.Fatalf("The sandbox path %s is not getting cleanup event after twice the cleanup period", s.Key()) if wait {
t.Fatalf("The sandbox path %s is not getting cleaned up even after twice the cleanup period", s.Key())
} else {
t.Fatalf("The sandbox path %s is not cleaned up after running gc", s.Key())
}
} }
} }

View file

@ -54,7 +54,7 @@ func TestSandboxCreate(t *testing.T) {
verifySandbox(t, s) verifySandbox(t, s)
s.Destroy() s.Destroy()
verifyCleanup(t, s) verifyCleanup(t, s, true)
} }
func TestSandboxCreateTwice(t *testing.T) { func TestSandboxCreateTwice(t *testing.T) {
@ -77,6 +77,23 @@ func TestSandboxCreateTwice(t *testing.T) {
s.Destroy() s.Destroy()
} }
func TestSandboxGC(t *testing.T) {
key, err := newKey(t)
if err != nil {
t.Fatalf("Failed to obtain a key: %v", err)
}
s, err := NewSandbox(key, true)
if err != nil {
t.Fatalf("Failed to create a new sandbox: %v", err)
}
s.Destroy()
GC()
verifyCleanup(t, s, false)
}
func TestAddRemoveInterface(t *testing.T) { func TestAddRemoveInterface(t *testing.T) {
key, err := newKey(t) key, err := newKey(t)
if err != nil { if err != nil {