Quellcode durchsuchen

avoid re-reading json files when copying containers

Signed-off-by: Fabio Kung <fabio.kung@gmail.com>
Fabio Kung vor 8 Jahren
Ursprung
Commit
a43be3431e
4 geänderte Dateien mit 52 neuen und 29 gelöschten Zeilen
  1. 46 20
      container/container.go
  2. 3 7
      container/view.go
  3. 1 1
      daemon/container_operations.go
  4. 2 1
      daemon/daemon_unix.go

+ 46 - 20
container/container.go

@@ -1,6 +1,7 @@
 package container
 package container
 
 
 import (
 import (
+	"bytes"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
@@ -14,8 +15,6 @@ import (
 	"syscall"
 	"syscall"
 	"time"
 	"time"
 
 
-	"golang.org/x/net/context"
-
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	containertypes "github.com/docker/docker/api/types/container"
 	containertypes "github.com/docker/docker/api/types/container"
 	mounttypes "github.com/docker/docker/api/types/mount"
 	mounttypes "github.com/docker/docker/api/types/mount"
@@ -45,6 +44,7 @@ import (
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
 	agentexec "github.com/docker/swarmkit/agent/exec"
 	agentexec "github.com/docker/swarmkit/agent/exec"
+	"golang.org/x/net/context"
 )
 )
 
 
 const configFileName = "config.v2.json"
 const configFileName = "config.v2.json"
@@ -154,36 +154,48 @@ func (container *Container) FromDisk() error {
 	return container.readHostConfig()
 	return container.readHostConfig()
 }
 }
 
 
-// ToDisk saves the container configuration on disk.
-func (container *Container) toDisk() error {
+// toDisk saves the container configuration on disk and returns a deep copy.
+func (container *Container) toDisk() (*Container, error) {
+	var (
+		buf      bytes.Buffer
+		deepCopy Container
+	)
 	pth, err := container.ConfigPath()
 	pth, err := container.ConfigPath()
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
 
 
-	jsonSource, err := ioutils.NewAtomicFileWriter(pth, 0644)
+	// Save container settings
+	f, err := ioutils.NewAtomicFileWriter(pth, 0644)
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
-	defer jsonSource.Close()
+	defer f.Close()
 
 
-	enc := json.NewEncoder(jsonSource)
+	w := io.MultiWriter(&buf, f)
+	if err := json.NewEncoder(w).Encode(container); err != nil {
+		return nil, err
+	}
 
 
-	// Save container settings
-	if err := enc.Encode(container); err != nil {
-		return err
+	if err := json.NewDecoder(&buf).Decode(&deepCopy); err != nil {
+		return nil, err
+	}
+	deepCopy.HostConfig, err = container.WriteHostConfig()
+	if err != nil {
+		return nil, err
 	}
 	}
 
 
-	return container.WriteHostConfig()
+	return &deepCopy, nil
 }
 }
 
 
 // CheckpointTo makes the Container's current state visible to queries, and persists state.
 // CheckpointTo makes the Container's current state visible to queries, and persists state.
 // Callers must hold a Container lock.
 // Callers must hold a Container lock.
 func (container *Container) CheckpointTo(store ViewDB) error {
 func (container *Container) CheckpointTo(store ViewDB) error {
-	if err := container.toDisk(); err != nil {
+	deepCopy, err := container.toDisk()
+	if err != nil {
 		return err
 		return err
 	}
 	}
-	return store.Save(container)
+	return store.Save(deepCopy)
 }
 }
 
 
 // readHostConfig reads the host configuration from disk for the container.
 // readHostConfig reads the host configuration from disk for the container.
@@ -215,20 +227,34 @@ func (container *Container) readHostConfig() error {
 	return nil
 	return nil
 }
 }
 
 
-// WriteHostConfig saves the host configuration on disk for the container.
-func (container *Container) WriteHostConfig() error {
+// WriteHostConfig saves the host configuration on disk for the container,
+// and returns a deep copy of the saved object. Callers must hold a Container lock.
+func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error) {
+	var (
+		buf      bytes.Buffer
+		deepCopy containertypes.HostConfig
+	)
+
 	pth, err := container.HostConfigPath()
 	pth, err := container.HostConfigPath()
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
 
 
 	f, err := ioutils.NewAtomicFileWriter(pth, 0644)
 	f, err := ioutils.NewAtomicFileWriter(pth, 0644)
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
 	defer f.Close()
 	defer f.Close()
 
 
-	return json.NewEncoder(f).Encode(&container.HostConfig)
+	w := io.MultiWriter(&buf, f)
+	if err := json.NewEncoder(w).Encode(&container.HostConfig); err != nil {
+		return nil, err
+	}
+
+	if err := json.NewDecoder(&buf).Decode(&deepCopy); err != nil {
+		return nil, err
+	}
+	return &deepCopy, nil
 }
 }
 
 
 // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
 // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir

+ 3 - 7
container/view.go

@@ -90,16 +90,12 @@ func (db *memDB) Snapshot(index *registrar.Registrar) View {
 	}
 	}
 }
 }
 
 
-// Save atomically updates the in-memory store from the current on-disk state of a Container.
+// Save atomically updates the in-memory store state for a Container.
+// Only read only (deep) copies of containers may be passed in.
 func (db *memDB) Save(c *Container) error {
 func (db *memDB) Save(c *Container) error {
 	txn := db.store.Txn(true)
 	txn := db.store.Txn(true)
 	defer txn.Commit()
 	defer txn.Commit()
-	deepCopy := NewBaseContainer(c.ID, c.Root)
-	err := deepCopy.FromDisk()
-	if err != nil {
-		return err
-	}
-	return txn.Insert(memdbTable, deepCopy)
+	return txn.Insert(memdbTable, c)
 }
 }
 
 
 // Delete removes an item by ID
 // Delete removes an item by ID

+ 1 - 1
daemon/container_operations.go

@@ -579,7 +579,7 @@ func (daemon *Daemon) allocateNetwork(container *container.Container) error {
 
 
 	}
 	}
 
 
-	if err := container.WriteHostConfig(); err != nil {
+	if _, err := container.WriteHostConfig(); err != nil {
 		return err
 		return err
 	}
 	}
 	networkActions.WithValues("allocate").UpdateSince(start)
 	networkActions.WithValues("allocate").UpdateSince(start)

+ 2 - 1
daemon/daemon_unix.go

@@ -1146,7 +1146,8 @@ func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *
 
 
 	// After we load all the links into the daemon
 	// After we load all the links into the daemon
 	// set them to nil on the hostconfig
 	// set them to nil on the hostconfig
-	return container.WriteHostConfig()
+	_, err := container.WriteHostConfig()
+	return err
 }
 }
 
 
 // conditionalMountOnStart is a platform specific helper function during the
 // conditionalMountOnStart is a platform specific helper function during the