@@ -33,12 +33,23 @@ class InstanceNUMACell(base.NovaEphemeralObject,
3333 # Version 1.2: Add cpu_pinning_raw and topology fields
3434 # Version 1.3: Add cpu_policy and cpu_thread_policy fields
3535 # Version 1.4: Add cpuset_reserved field
36- VERSION = '1.4'
36+ # Version 1.5: Add pcpuset field
37+ VERSION = '1.5'
3738
3839 def obj_make_compatible (self , primitive , target_version ):
3940 super (InstanceNUMACell , self ).obj_make_compatible (primitive ,
40- target_version )
41+ target_version )
4142 target_version = versionutils .convert_version_to_tuple (target_version )
43+ # NOTE(huaqiang): Since version 1.5, 'cpuset' is modified to track the
44+ # unpinned CPUs only, with pinned CPUs tracked via 'pcpuset' instead.
45+ # For a backward compatibility, move the 'dedicated' instance CPU list
46+ # from 'pcpuset' to 'cpuset'.
47+ if target_version < (1 , 5 ):
48+ if (primitive ['cpu_policy' ] ==
49+ obj_fields .CPUAllocationPolicy .DEDICATED ):
50+ primitive ['cpuset' ] = primitive ['pcpuset' ]
51+ primitive .pop ('pcpuset' , None )
52+
4253 if target_version < (1 , 4 ):
4354 primitive .pop ('cpuset_reserved' , None )
4455
@@ -49,6 +60,10 @@ def obj_make_compatible(self, primitive, target_version):
4960 fields = {
5061 'id' : obj_fields .IntegerField (),
5162 'cpuset' : obj_fields .SetOfIntegersField (),
63+ 'pcpuset' : obj_fields .SetOfIntegersField (),
64+ # These physical CPUs are reserved for use by the hypervisor
65+ 'cpuset_reserved' : obj_fields .SetOfIntegersField (nullable = True ,
66+ default = None ),
5267 'memory' : obj_fields .IntegerField (),
5368 'pagesize' : obj_fields .IntegerField (nullable = True ,
5469 default = None ),
@@ -60,19 +75,20 @@ def obj_make_compatible(self, primitive, target_version):
6075 default = None ),
6176 'cpu_thread_policy' : obj_fields .CPUThreadAllocationPolicyField (
6277 nullable = True , default = None ),
63- # These physical CPUs are reserved for use by the hypervisor
64- 'cpuset_reserved' : obj_fields .SetOfIntegersField (nullable = True ,
65- default = None ),
6678 }
6779
6880 cpu_pinning = obj_fields .DictProxyField ('cpu_pinning_raw' )
6981
7082 def __len__ (self ):
71- return len (self .cpuset )
83+ return len (self .total_cpus )
84+
85+ @property
86+ def total_cpus (self ):
87+ return self .cpuset | self .pcpuset
7288
7389 @property
7490 def siblings (self ):
75- cpu_list = sorted (list (self .cpuset ))
91+ cpu_list = sorted (list (self .total_cpus ))
7692
7793 threads = 0
7894 if ('cpu_topology' in self ) and self .cpu_topology :
@@ -83,7 +99,7 @@ def siblings(self):
8399 return list (map (set , zip (* [iter (cpu_list )] * threads )))
84100
85101 def pin (self , vcpu , pcpu ):
86- if vcpu not in self .cpuset :
102+ if vcpu not in self .pcpuset :
87103 return
88104 pinning_dict = self .cpu_pinning or {}
89105 pinning_dict [vcpu ] = pcpu
@@ -115,7 +131,7 @@ class InstanceNUMATopology(base.NovaObject,
115131
116132 def obj_make_compatible (self , primitive , target_version ):
117133 super (InstanceNUMATopology , self ).obj_make_compatible (primitive ,
118- target_version )
134+ target_version )
119135 target_version = versionutils .convert_version_to_tuple (target_version )
120136 if target_version < (1 , 3 ):
121137 primitive .pop ('emulator_threads_policy' , None )
@@ -136,11 +152,43 @@ def obj_from_db_obj(cls, context, instance_uuid, db_obj):
136152
137153 if 'nova_object.name' in primitive :
138154 obj = cls .obj_from_primitive (primitive )
155+ cls ._migrate_legacy_dedicated_instance_cpuset (
156+ context , instance_uuid , obj )
139157 else :
140158 obj = cls ._migrate_legacy_object (context , instance_uuid , primitive )
141159
142160 return obj
143161
162+ # TODO(huaqiang): Remove after Wallaby once we are sure these objects have
163+ # been loaded at least once.
164+ @classmethod
165+ def _migrate_legacy_dedicated_instance_cpuset (cls , context , instance_uuid ,
166+ obj ):
167+ # NOTE(huaqiang): We may meet some topology object with the old version
168+ # 'InstanceNUMACell' cells, in that case, the 'dedicated' CPU is kept
169+ # in 'InstanceNUMACell.cpuset' field, but it should be kept in
170+ # 'InstanceNUMACell.pcpuset' field since Victoria. Making an upgrade
171+ # and persisting to database.
172+ update_db = False
173+ for cell in obj .cells :
174+ if len (cell .cpuset ) == 0 :
175+ continue
176+
177+ if cell .cpu_policy != obj_fields .CPUAllocationPolicy .DEDICATED :
178+ continue
179+
180+ cell .pcpuset = cell .cpuset
181+ cell .cpuset = set ()
182+ update_db = True
183+
184+ if update_db :
185+ db_obj = jsonutils .dumps (obj .obj_to_primitive ())
186+ values = {
187+ 'numa_topology' : db_obj ,
188+ }
189+ db .instance_extra_update_by_uuid (context , instance_uuid ,
190+ values )
191+
144192 # TODO(stephenfin): Remove in X or later, once this has bedded in
145193 @classmethod
146194 def _migrate_legacy_object (cls , context , instance_uuid , primitive ):
@@ -161,6 +209,7 @@ def _migrate_legacy_object(cls, context, instance_uuid, primitive):
161209 InstanceNUMACell (
162210 id = cell .get ('id' ),
163211 cpuset = hardware .parse_cpu_spec (cell .get ('cpus' , '' )),
212+ pcpuset = set (),
164213 memory = cell .get ('mem' , {}).get ('total' , 0 ),
165214 pagesize = cell .get ('pagesize' ),
166215 ) for cell in primitive .get ('cells' , [])
0 commit comments