Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: scripts/common/slave_alloc.py

Issue 1393893004: Add `slave_alloc_update` tool. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Library to generate, maintain, and read static slave pool maps.""" 5 """Library to generate, maintain, and read static slave pool maps."""
6 6
7 import collections 7 import collections
8 import itertools 8 import itertools
9 import json 9 import json
10 import os 10 import os
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 external JSON file. This can be used to enforce class-to-slave mapping 67 external JSON file. This can be used to enforce class-to-slave mapping
68 consistency (i.e., builder affinity). 68 consistency (i.e., builder affinity).
69 69
70 When a new allocation is performed, the SlaveAllocator's State is updated, and 70 When a new allocation is performed, the SlaveAllocator's State is updated, and
71 subsequent operations will prefer the previous layout. 71 subsequent operations will prefer the previous layout.
72 """ 72 """
73 73
74 # The default path to load/save state to, if none is specified. 74 # The default path to load/save state to, if none is specified.
75 DEFAULT_STATE_PATH = 'slave_pool.json' 75 DEFAULT_STATE_PATH = 'slave_pool.json'
76 76
77 def __init__(self): 77 def __init__(self, state_path=None, list_unallocated=False):
78 """Initializes a new slave pool instance.""" 78 """Initializes a new slave pool instance.
79
80 Args:
81 state_path (str): The path (relative or absolute) of the allocation
82 save-state JSON file. If None, DEFAULT_STATE_PATH will be used.
83 list_unallocated (bool): Include an entry listing unallocated slaves.
84 This entry will be ignored for operations, but can be useful when
85 generating expectations.
86 """
87 self._state_path = state_path
88 self._list_unallocated = list_unallocated
89
79 self._state = None 90 self._state = None
80 self._pools = {} 91 self._pools = {}
81 self._classes = {} 92 self._classes = {}
82 self._membership = {} 93 self._membership = {}
83 self._all_slaves = {} 94 self._all_slaves = {}
84 95
96 @property
97 def state_path(self):
98 return self._state_path or self.DEFAULT_STATE_PATH
99
85 def LoadStateDict(self, state_class_map=None): 100 def LoadStateDict(self, state_class_map=None):
86 """Loads previous allocation state from a state dictionary. 101 """Loads previous allocation state from a state dictionary.
87 102
88 The state dictionary is structured: 103 The state dictionary is structured:
89 <class-name>: { 104 <class-name>: {
90 <class-subtype>: [ 105 <class-subtype>: [
91 <slave> 106 <slave>
92 ... 107 ...
93 ], 108 ],
94 ... 109 ...
95 } 110 }
96 111
97 Args: 112 Args:
98 state_class_map (dict): A state class map dictionary. If None or empty, 113 state_class_map (dict): A state class map dictionary. If None or empty,
99 the current state will be cleared. 114 the current state will be cleared.
100 """ 115 """
101 if not state_class_map: 116 if not state_class_map:
102 self._state = None 117 self._state = None
103 return 118 return
104 119
105 class_map = {} 120 class_map = {}
106 for class_name, class_name_entry in state_class_map.iteritems(): 121 for class_name, class_name_entry in state_class_map.iteritems():
107 for subtype, slave_list in class_name_entry.iteritems(): 122 for subtype, slave_list in class_name_entry.iteritems():
108 cls = SlaveClass(name=class_name, subtype=subtype) 123 cls = SlaveClass(name=class_name, subtype=subtype)
109 class_map.setdefault(cls, []).extend(str(s) for s in slave_list) 124 class_map.setdefault(cls, []).extend(str(s) for s in slave_list)
110 self._state = SlaveState( 125 self._state = SlaveState(
111 class_map=class_map, 126 class_map=class_map,
112 unallocated=None) 127 unallocated=None)
113 128
114 def LoadState(self, path=None, enforce=True): 129 def LoadState(self, enforce=True):
115 """Loads slave pools from the store, replacing the current in-memory set. 130 """Loads slave pools from the store, replacing the current in-memory set.
116 131
117 Args: 132 Args:
118 path (str): If provided, the path to load from; otherwise,
119 DEFAULT_STATE_PATH will be used.
120 enforce (bool): If True, raise an IOError if the state file does not 133 enforce (bool): If True, raise an IOError if the state file does not
121 exist or a ValueError if it could not be loaded. 134 exist or a ValueError if it could not be loaded.
122 """ 135 """
123 state = {} 136 state = {}
124 path = path or self.DEFAULT_STATE_PATH 137 if not os.path.exists(self.state_path):
125 if not os.path.exists(path):
126 if enforce: 138 if enforce:
127 raise IOError("State path does not exist: %s" % (path,)) 139 raise IOError("State path does not exist: %s" % (self.state_path,))
128 try: 140 try:
129 with open(path or self.DEFAULT_STATE_PATH, 'r') as fd: 141 with open(self.state_path, 'r') as fd:
130 state = json.load(fd) 142 state = json.load(fd)
131 except (IOError, ValueError): 143 except (IOError, ValueError):
132 if enforce: 144 if enforce:
133 raise 145 raise
134 self.LoadStateDict(state.get('class_map')) 146 self.LoadStateDict(state.get('class_map'))
135 147
136 def SaveState(self, path=None, list_unallocated=False): 148 def SaveState(self):
137 """Saves the current slave pool set to the store path. 149 """Saves the current slave pool set to the store path."""
138
139 Args:
140 path (str): The path of the state file. If None, use DEFAULT_STATE_PATH.
141 list_unallocated (bool): Include an entry listing unallocated slaves.
142 This entry will be ignored for operations, but can be useful when
143 generating expectations.
144 """
145 state_dict = {} 150 state_dict = {}
146 if self._state and self._state.class_map: 151 if self._state and self._state.class_map:
147 class_map = state_dict['class_map'] = {} 152 class_map = state_dict['class_map'] = {}
148 for sc, slave_list in self._state.class_map.iteritems(): 153 for sc, slave_list in self._state.class_map.iteritems():
149 class_dict = class_map.setdefault(sc.name, {}) 154 class_dict = class_map.setdefault(sc.name, {})
150 subtype_dict = class_dict.setdefault(sc.subtype, []) 155 subtype_dict = class_dict.setdefault(sc.subtype, [])
151 subtype_dict.extend(slave_list) 156 subtype_dict.extend(slave_list)
152 157
153 if list_unallocated: 158 if self._list_unallocated:
154 state_dict['unallocated'] = list(self._state.unallocated or ()) 159 state_dict['unallocated'] = list(self._state.unallocated or ())
155 160
156 with open(path or self.DEFAULT_STATE_PATH, 'w') as fd: 161 with open(self.state_path, 'w') as fd:
157 json.dump(state_dict, fd, sort_keys=True, indent=2) 162 json.dump(state_dict, fd, sort_keys=True, indent=2)
158 163
159 def AddPool(self, name, *slaves): 164 def AddPool(self, name, *slaves):
160 """Returns (str): The slave pool that was allocated (for chaining). 165 """Returns (str): The slave pool that was allocated (for chaining).
161 166
162 Args: 167 Args:
163 name (str): The slave pool name. 168 name (str): The slave pool name.
164 slaves: Slave name strings that belong to this pool. 169 slaves: Slave name strings that belong to this pool.
165 """ 170 """
166 pool = self._pools.get(name) 171 pool = self._pools.get(name)
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 339
335 # Convert SlaveMapEntry fields to immutable form. 340 # Convert SlaveMapEntry fields to immutable form.
336 result = SlaveMap( 341 result = SlaveMap(
337 entries={}, 342 entries={},
338 unallocated=frozenset(n_state.unallocated)) 343 unallocated=frozenset(n_state.unallocated))
339 for k, v in slave_map_entries.iteritems(): 344 for k, v in slave_map_entries.iteritems():
340 result.entries[k] = SlaveMapEntry( 345 result.entries[k] = SlaveMapEntry(
341 classes=frozenset(v.classes), 346 classes=frozenset(v.classes),
342 keys=tuple(sorted(v.keys))) 347 keys=tuple(sorted(v.keys)))
343 return result 348 return result
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698