Browse Source

Remove pre-defined networks from package init

This moves the initialization of the pre-defined networks to where it's
used instead of in package init.
This reason for this change is having this be populated in `init()`
causes it to always consume cpu, and memory (4.3MB of memory), to
populate even if the package is unused (like for instnace, in a re-exec).

Here is a memory profile of docker/docker just after starting the daemon of the
top 10 largest memory consumers:

Before:
```
      flat  flat%   sum%        cum   cum%
         0     0%     0%    11.89MB 95.96%  runtime.goexit
         0     0%     0%     6.79MB 54.82%  runtime.main
         0     0%     0%     5.79MB 46.74%  main.init
         0     0%     0%     4.79MB 38.67%  github.com/docker/docker/api/server/router/network.init
         0     0%     0%     4.79MB 38.67%  github.com/docker/libnetwork.init
         0     0%     0%     4.29MB 34.63%  github.com/docker/libnetwork/ipam.init
         0     0%     0%     4.29MB 34.63%  github.com/docker/libnetwork/ipams/builtin.init
         0     0%     0%     4.29MB 34.63%  github.com/docker/libnetwork/ipamutils.init
         0     0%     0%     4.29MB 34.63%  github.com/docker/libnetwork/ipamutils.init.1
    4.29MB 34.63% 34.63%     4.29MB 34.63%  github.com/docker/libnetwork/ipamutils.initGranularPredefinedNetworks
```

After:
```
      flat  flat%   sum%        cum   cum%
         0     0%     0%  4439.37kB 89.66%  runtime.goexit
         0     0%     0%  4439.37kB 89.66%  runtime.main
         0     0%     0%  3882.11kB 78.40%  github.com/docker/docker/cli.(*Cli).Run
         0     0%     0%  3882.11kB 78.40%  main.main
 3882.11kB 78.40% 78.40%  3882.11kB 78.40%  reflect.callMethod
         0     0% 78.40%  3882.11kB 78.40%  reflect.methodValueCall
         0     0% 78.40%   557.26kB 11.25%  github.com/docker/docker/api/server.init
  557.26kB 11.25% 89.66%   557.26kB 11.25%  html.init
         0     0% 89.66%   557.26kB 11.25%  html/template.init
         0     0% 89.66%   557.26kB 11.25%  main.init
```

Now, of course the docker daemon will still need to consume this memory, but
at least now re-execs and such won't have to re-init these variables.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Brian Goff 9 years ago
parent
commit
22801e071f

+ 4 - 0
libnetwork/drivers/bridge/bridge_test.go

@@ -15,6 +15,10 @@ import (
 	"github.com/docker/libnetwork/types"
 )
 
+func init() {
+	ipamutils.InitNetworks()
+}
+
 func getIPv4Data(t *testing.T) []driverapi.IPAMData {
 	ipd := driverapi.IPAMData{AddressSpace: "full"}
 	nw, _, err := ipamutils.ElectInterfaceAddresses("")

+ 1 - 0
libnetwork/ipam/allocator_test.go

@@ -46,6 +46,7 @@ func randomLocalStore() (datastore.DataStore, error) {
 }
 
 func getAllocator() (*Allocator, error) {
+	ipamutils.InitNetworks()
 	ds, err := randomLocalStore()
 	if err != nil {
 		return nil, err

+ 4 - 0
libnetwork/ipams/builtin/builtin_unix.go

@@ -8,6 +8,7 @@ import (
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/ipam"
 	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/ipamutils"
 )
 
 // Init registers the built-in ipam service with libnetwork
@@ -28,6 +29,9 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
 			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
 		}
 	}
+
+	ipamutils.InitNetworks()
+
 	a, err := ipam.NewAllocator(localDs, globalDs)
 	if err != nil {
 		return err

+ 12 - 4
libnetwork/ipamutils/utils.go

@@ -1,7 +1,10 @@
 // Package ipamutils provides utililty functions for ipam management
 package ipamutils
 
-import "net"
+import (
+	"net"
+	"sync"
+)
 
 var (
 	// PredefinedBroadNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
@@ -10,11 +13,16 @@ var (
 	// PredefinedGranularNetworks contains a list of 64K IPv4 private networks with host size 8
 	// (10.x.x.x/24) which do not overlap with the networks in `PredefinedBroadNetworks`
 	PredefinedGranularNetworks []*net.IPNet
+
+	initNetworksOnce sync.Once
 )
 
-func init() {
-	PredefinedBroadNetworks = initBroadPredefinedNetworks()
-	PredefinedGranularNetworks = initGranularPredefinedNetworks()
+// InitNetworks initializes the pre-defined networks used by the  built-in IP allocator
+func InitNetworks() {
+	initNetworksOnce.Do(func() {
+		PredefinedBroadNetworks = initBroadPredefinedNetworks()
+		PredefinedGranularNetworks = initGranularPredefinedNetworks()
+	})
 }
 
 func initBroadPredefinedNetworks() []*net.IPNet {

+ 2 - 0
libnetwork/ipamutils/utils_linux.go

@@ -22,6 +22,8 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
 		err    error
 	)
 
+	InitNetworks()
+
 	defer osl.InitOSContext()()
 
 	link, _ := netlink.LinkByName(name)

+ 4 - 0
libnetwork/ipamutils/utils_test.go

@@ -9,6 +9,10 @@ import (
 	"github.com/vishvananda/netlink"
 )
 
+func init() {
+	InitNetworks()
+}
+
 func TestGranularPredefined(t *testing.T) {
 	for _, nw := range PredefinedGranularNetworks {
 		if ones, bits := nw.Mask.Size(); bits != 32 || ones != 24 {