Browse Source

Merge pull request #262 from mrjana/cnm_integ

Add support to trigger immediate garbage collection
Madhu Venugopal 10 years ago
parent
commit
48374f367f

+ 8 - 0
libnetwork/controller.go

@@ -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()
+}

+ 28 - 1
libnetwork/sandbox/namespace_linux.go

@@ -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 {

+ 10 - 3
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 {
 	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())
+		}
 	}
 	}
 }
 }

+ 18 - 1
libnetwork/sandbox/sandbox_test.go

@@ -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 {