[lxc-devel] [lxd/master] Improve performance of setting volatile keys
stgraber on Github
lxc-bot at linuxcontainers.org
Thu May 9 19:15:30 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190509/b21318e0/attachment.bin>
-------------- next part --------------
From 3f024abeae722ffc2fe1f62fed15a4ef1d45e526 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 9 May 2019 15:13:56 -0400
Subject: [PATCH 1/2] lxd/db: Introduce ContainerConfigUpdate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/db/containers.go | 48 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 152df5d2df..8b453e7225 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -524,6 +524,54 @@ func (c *ClusterTx) ContainerConfigInsert(id int, config map[string]string) erro
return ContainerConfigInsert(c.tx, id, config)
}
+// ContainerConfigUpdate inserts/updates/deletes the provided keys
+func (c *ClusterTx) ContainerConfigUpdate(id int, values map[string]string) error {
+ changes := map[string]string{}
+ deletes := []string{}
+
+ // Figure out which key to set/unset
+ for key, value := range values {
+ if value == "" {
+ deletes = append(deletes, key)
+ continue
+ }
+ changes[key] = value
+ }
+
+ // Insert/update keys
+ if len(changes) > 0 {
+ query := fmt.Sprintf("INSERT OR REPLACE INTO containers_config (container_id, key, value) VALUES")
+ exprs := []string{}
+ params := []interface{}{}
+ for key, value := range changes {
+ exprs = append(exprs, "(?, ?, ?)")
+ params = append(params, []interface{}{id, key, value}...)
+ }
+
+ query += strings.Join(exprs, ",")
+ _, err := c.tx.Exec(query, params...)
+ if err != nil {
+ return err
+ }
+ }
+
+ // Delete keys
+ if len(deletes) > 0 {
+ query := fmt.Sprintf("DELETE FROM containers_config WHERE key IN %s AND container_id=?", query.Params(len(deletes)))
+ params := []interface{}{}
+ for _, key := range deletes {
+ params = append(params, key)
+ }
+
+ _, err := c.tx.Exec(query, params...)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
// ContainerRemove removes the container with the given name from the database.
func (c *Cluster) ContainerRemove(project, name string) error {
return c.Transaction(func(tx *ClusterTx) error {
From d89d1f20bc4ef969fffd096d0f86afe89511678e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 9 May 2019 15:14:23 -0400
Subject: [PATCH 2/2] lxd/containers: Replace ConfigKeySet with VolatileSet
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/container.go | 4 ++--
lxd/container_lxc.go | 49 +++++++++++++++++++++++++-------------------
lxd/containers.go | 4 ++--
lxd/storage.go | 2 +-
4 files changed, 33 insertions(+), 26 deletions(-)
diff --git a/lxd/container.go b/lxd/container.go
index 1a6a1b4532..7295d06917 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -637,7 +637,7 @@ type container interface {
// Live configuration
CGroupGet(key string) (string, error)
CGroupSet(key string, value string) error
- ConfigKeySet(key string, value string) error
+ VolatileSet(changes map[string]string) error
// File handling
FileExists(path string) error
@@ -1349,7 +1349,7 @@ func containerConfigureInternal(c container) error {
if rootDiskDevice["size"] != "" {
storageTypeName := storage.GetStorageTypeName()
if (storageTypeName == "lvm" || storageTypeName == "ceph") && c.IsRunning() {
- err = c.ConfigKeySet("volatile.apply_quota", rootDiskDevice["size"])
+ err = c.VolatileSet(map[string]string{"volatile.apply_quota": rootDiskDevice["size"]})
if err != nil {
return err
}
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 1a65e9c47a..481cec94d7 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -456,14 +456,14 @@ func containerLXCCreate(s *state.State, args db.ContainerArgs) (container, error
jsonIdmap = "[]"
}
- err = c.ConfigKeySet("volatile.idmap.next", jsonIdmap)
+ err = c.VolatileSet(map[string]string{"volatile.idmap.next": jsonIdmap})
if err != nil {
c.Delete()
logger.Error("Failed creating container", ctxMap)
return nil, err
}
- err = c.ConfigKeySet("volatile.idmap.base", fmt.Sprintf("%v", base))
+ err = c.VolatileSet(map[string]string{"volatile.idmap.base": fmt.Sprintf("%v", base)})
if err != nil {
c.Delete()
logger.Error("Failed creating container", ctxMap)
@@ -475,7 +475,7 @@ func containerLXCCreate(s *state.State, args db.ContainerArgs) (container, error
// Set last_state if not currently set
if c.localConfig["volatile.last_state.idmap"] == "" {
- err = c.ConfigKeySet("volatile.last_state.idmap", "[]")
+ err = c.VolatileSet(map[string]string{"volatile.last_state.idmap": "[]"})
if err != nil {
c.Delete()
logger.Error("Failed creating container", ctxMap)
@@ -2158,7 +2158,7 @@ func (c *containerLXC) startCommon() (string, error) {
jsonDiskIdmap = string(idmapBytes)
}
- err = c.ConfigKeySet("volatile.last_state.idmap", jsonDiskIdmap)
+ err = c.VolatileSet(map[string]string{"volatile.last_state.idmap": jsonDiskIdmap})
if err != nil {
return "", errors.Wrapf(err, "Set volatile.last_state.idmap config key on container %q (id %d)", c.name, c.id)
}
@@ -2177,7 +2177,7 @@ func (c *containerLXC) startCommon() (string, error) {
}
if c.localConfig["volatile.idmap.current"] != string(idmapBytes) {
- err = c.ConfigKeySet("volatile.idmap.current", string(idmapBytes))
+ err = c.VolatileSet(map[string]string{"volatile.idmap.current": string(idmapBytes)})
if err != nil {
return "", errors.Wrapf(err, "Set volatile.idmap.current config key on container %q (id %d)", c.name, c.id)
}
@@ -3965,26 +3965,33 @@ func (c *containerLXC) CGroupSet(key string, value string) error {
return nil
}
-func (c *containerLXC) ConfigKeySet(key string, value string) error {
- c.localConfig[key] = value
-
- args := db.ContainerArgs{
- Architecture: c.architecture,
- Config: c.localConfig,
- Description: c.description,
- Devices: c.localDevices,
- Ephemeral: c.ephemeral,
- Profiles: c.profiles,
- Project: c.project,
- ExpiryDate: c.expiryDate,
+func (c *containerLXC) VolatileSet(changes map[string]string) error {
+ // Sanity check
+ for key := range changes {
+ if !strings.HasPrefix(key, "volatile.") {
+ return fmt.Errorf("Only volatile keys can be modified with VolatileSet")
+ }
}
- err := c.Update(args, false)
+ // Update the database
+ err := c.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
+ return tx.ContainerConfigUpdate(c.id, changes)
+ })
if err != nil {
- errors.Wrap(err, "Failed to update container")
+ return errors.Wrap(err, "Failed to update database")
}
- return err
+ // Apply the change locally
+ for key, value := range changes {
+ if value == "" {
+ delete(c.localConfig, key)
+ continue
+ }
+
+ c.localConfig[key] = value
+ }
+
+ return nil
}
type backupFile struct {
@@ -5730,7 +5737,7 @@ func (c *containerLXC) TemplateApply(trigger string) error {
// "create" and "copy" are deferred until next start
if shared.StringInSlice(trigger, []string{"create", "copy"}) {
// The two events are mutually exclusive so only keep the last one
- err := c.ConfigKeySet("volatile.apply_template", trigger)
+ err := c.VolatileSet(map[string]string{"volatile.apply_template": trigger})
if err != nil {
return errors.Wrap(err, "Failed to set apply_template volatile key")
}
diff --git a/lxd/containers.go b/lxd/containers.go
index 49625cfd0b..4f541ba0dd 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -290,12 +290,12 @@ func containersShutdown(s *state.State) error {
go func(c container, lastState string) {
c.Shutdown(time.Second * time.Duration(timeoutSeconds))
c.Stop(false)
- c.ConfigKeySet("volatile.last_state.power", lastState)
+ c.VolatileSet(map[string]string{"volatile.last_state.power": lastState})
wg.Done()
}(c, lastState)
} else {
- c.ConfigKeySet("volatile.last_state.power", lastState)
+ c.VolatileSet(map[string]string{"volatile.last_state.power": lastState})
}
}
wg.Wait()
diff --git a/lxd/storage.go b/lxd/storage.go
index 2e07d53039..f8c7e70c45 100644
--- a/lxd/storage.go
+++ b/lxd/storage.go
@@ -777,7 +777,7 @@ func resetContainerDiskIdmap(container container, srcIdmap *idmap.IdmapSet) erro
jsonIdmap = "[]"
}
- err := container.ConfigKeySet("volatile.last_state.idmap", jsonIdmap)
+ err := container.VolatileSet(map[string]string{"volatile.last_state.idmap": jsonIdmap})
if err != nil {
return err
}
More information about the lxc-devel
mailing list