From 4fae38c585c6ba83fb4649d324e04c8e5b217899 Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Tue, 27 Oct 2009 15:27:44 -0400
Subject: [PATCH] ConfigWriter: move _temporary_ids to reservation

In order to do this we need to pass a job id when reserving a resource.
We have one during _EnsureUUIDs because we passed it in from AddNode and
AddInstance. During config upgrade we use a fake job ID which we then
cleanup. We can delete the _CleanupTemporaryIDs code, since the cleanup
is going to be done at job finish time by mcpu.

Signed-off-by: Guido Trotter <ultrotter@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/cmdlib.py |  2 +-
 lib/config.py | 49 +++++++++++++++++++------------------------------
 2 files changed, 20 insertions(+), 31 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index abf9e70aa..31d0b6173 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -5311,7 +5311,7 @@ def _GenerateUniqueNames(lu, exts):
   """
   results = []
   for val in exts:
-    new_id = lu.cfg.GenerateUniqueID()
+    new_id = lu.cfg.GenerateUniqueID(lu.proc.GetECId())
     results.append("%s%s" % (new_id, val))
   return results
 
diff --git a/lib/config.py b/lib/config.py
index 3f5119f3e..58b412ce2 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -47,6 +47,9 @@ from ganeti import serializer
 
 _config_lock = locking.SharedLock()
 
+# job id used for resource management at config upgrade time
+_UPGRADE_CONFIG_JID="jid-cfg-upgrade"
+
 
 def _ValidateConfig(data):
   """Verifies that a configuration objects looks valid.
@@ -132,7 +135,7 @@ class ConfigWriter:
       self._cfg_file = constants.CLUSTER_CONF_FILE
     else:
       self._cfg_file = cfg_file
-    self._temporary_ids = set()
+    self._temporary_ids = TemporaryReservationManager()
     self._temporary_drbds = {}
     self._temporary_macs = set()
     # Note: in order to prevent errors when resolving our name in
@@ -225,14 +228,14 @@ class ConfigWriter:
     """
     existing = set()
     if include_temporary:
-      existing.update(self._temporary_ids)
+      existing.update(self._temporary_ids.GetReserved())
     existing.update(self._AllLVs())
     existing.update(self._config_data.instances.keys())
     existing.update(self._config_data.nodes.keys())
     existing.update([i.uuid for i in self._AllUUIDObjects() if i.uuid])
     return existing
 
-  def _GenerateUniqueID(self):
+  def _GenerateUniqueID(self, ec_id):
     """Generate an unique UUID.
 
     This checks the current node, instances and disk names for
@@ -242,33 +245,20 @@ class ConfigWriter:
     @return: the unique id
 
     """
-    existing = self._AllIDs(include_temporary=True)
-    retries = 64
-    while retries > 0:
-      unique_id = utils.NewUUID()
-      if unique_id not in existing and unique_id is not None:
-        break
-    else:
-      raise errors.ConfigurationError("Not able generate an unique ID"
-                                      " (last tried ID: %s" % unique_id)
-    self._temporary_ids.add(unique_id)
-    return unique_id
+    existing = self._AllIDs(include_temporary=False)
+    return self._temporary_ids.Generate(existing, utils.NewUUID, ec_id)
 
   @locking.ssynchronized(_config_lock, shared=1)
-  def GenerateUniqueID(self):
+  def GenerateUniqueID(self, ec_id):
     """Generate an unique ID.
 
     This is just a wrapper over the unlocked version.
 
-    """
-    return self._GenerateUniqueID()
-
-  def _CleanupTemporaryIDs(self):
-    """Cleanups the _temporary_ids structure.
+    @type ec_id: string
+    @param ec_id: unique id for the job to reserve the id to
 
     """
-    existing = self._AllIDs(include_temporary=False)
-    self._temporary_ids = self._temporary_ids - existing
+    return self._GenerateUniqueID(ec_id)
 
   def _AllMACs(self):
     """Return all MACs present in the config.
@@ -821,7 +811,7 @@ class ConfigWriter:
 
     """
     if not item.uuid:
-      item.uuid = self._GenerateUniqueID()
+      item.uuid = self._GenerateUniqueID(ec_id)
     elif item.uuid in self._AllIDs(temporary=True):
       raise errors.ConfigurationError("Cannot add '%s': UUID already in use" %
                                       (item.name, item.uuid))
@@ -1205,10 +1195,14 @@ class ConfigWriter:
     modified = False
     for item in self._AllUUIDObjects():
       if item.uuid is None:
-        item.uuid = self._GenerateUniqueID()
+        item.uuid = self._GenerateUniqueID(_UPGRADE_CONFIG_JID)
         modified = True
     if modified:
       self._WriteConfig()
+      # This is ok even if it acquires the internal lock, as _UpgradeConfig is
+      # only called at config init time, without the lock held
+      self.DropECReservations(_UPGRADE_CONFIG_JID)
+
 
   def _DistributeConfig(self, feedback_fn):
     """Distribute the configuration to the other nodes.
@@ -1260,11 +1254,6 @@ class ConfigWriter:
     """
     assert feedback_fn is None or callable(feedback_fn)
 
-    # First, cleanup the _temporary_ids set, if an ID is now in the
-    # other objects it should be discarded to prevent unbounded growth
-    # of that structure
-    self._CleanupTemporaryIDs()
-
     # Warn on config errors, but don't abort the save - the
     # configuration has already been modified, and we can't revert;
     # the best we can do is to warn the user and save as is, leaving
@@ -1441,5 +1430,5 @@ class ConfigWriter:
     """Drop per-execution-context reservations
 
     """
-    pass
+    self._temporary_ids.DropECReservations(ec_id)
 
-- 
GitLab