From 15ddc3717a9334ab1eb1738e86cc6961897aa873 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Fri, 5 Jun 2015 11:46:33 -0700 Subject: [PATCH] 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 --- libnetwork/controller.go | 8 +++++++ libnetwork/sandbox/namespace_linux.go | 29 +++++++++++++++++++++++- libnetwork/sandbox/sandbox_linux_test.go | 13 ++++++++--- libnetwork/sandbox/sandbox_test.go | 19 +++++++++++++++- 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/libnetwork/controller.go b/libnetwork/controller.go index d709d972b0..f5aaac5b37 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -59,6 +59,7 @@ import ( "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/hostdiscovery" + "github.com/docker/libnetwork/sandbox" "github.com/docker/libnetwork/types" "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(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. @@ -394,3 +398,7 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) { } return d, nil } + +func (c *controller) GC() { + sandbox.GC() +} diff --git a/libnetwork/sandbox/namespace_linux.go b/libnetwork/sandbox/namespace_linux.go index c368d54f41..3d8a98ccf6 100644 --- a/libnetwork/sandbox/namespace_linux.go +++ b/libnetwork/sandbox/namespace_linux.go @@ -25,6 +25,7 @@ var ( gpmLock sync.Mutex gpmWg sync.WaitGroup gpmCleanupPeriod = 60 * time.Second + gpmChan = make(chan chan struct{}) ) // The networkNamespace type is the linux implementation of the Sandbox @@ -56,7 +57,18 @@ func removeUnusedPaths() { period := gpmCleanupPeriod 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() pathList := make([]string, 0, len(garbagePathMap)) for path := range garbagePathMap { @@ -71,6 +83,9 @@ func removeUnusedPaths() { } gpmWg.Done() + if gcOk { + close(gc) + } } } @@ -86,6 +101,18 @@ func removeFromGarbagePaths(path string) { 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 // container id. func GenerateKey(containerID string) string { diff --git a/libnetwork/sandbox/sandbox_linux_test.go b/libnetwork/sandbox/sandbox_linux_test.go index b00d14f350..67175b11e3 100644 --- a/libnetwork/sandbox/sandbox_linux_test.go +++ b/libnetwork/sandbox/sandbox_linux_test.go @@ -153,9 +153,16 @@ func verifySandbox(t *testing.T, s Sandbox) { } } -func verifyCleanup(t *testing.T, s Sandbox) { - time.Sleep(time.Duration(gpmCleanupPeriod * 2)) +func verifyCleanup(t *testing.T, s Sandbox, wait bool) { + if wait { + time.Sleep(time.Duration(gpmCleanupPeriod * 2)) + } + 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()) + } } } diff --git a/libnetwork/sandbox/sandbox_test.go b/libnetwork/sandbox/sandbox_test.go index 639dc7917d..ca0d6ba1b3 100644 --- a/libnetwork/sandbox/sandbox_test.go +++ b/libnetwork/sandbox/sandbox_test.go @@ -54,7 +54,7 @@ func TestSandboxCreate(t *testing.T) { verifySandbox(t, s) s.Destroy() - verifyCleanup(t, s) + verifyCleanup(t, s, true) } func TestSandboxCreateTwice(t *testing.T) { @@ -77,6 +77,23 @@ func TestSandboxCreateTwice(t *testing.T) { 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) { key, err := newKey(t) if err != nil {