ninja_build/state.rs
1// Copyright 2011 Google Inc. All Rights Reserved.
2// Copyright 2017 The Ninja-rs Project Developers. All Rights Reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use std::rc::Rc;
17use std::cell::RefCell;
18use std::collections::{HashMap, HashSet, BTreeSet, BinaryHeap};
19use std::cmp::{PartialOrd, Ordering};
20
21use super::eval_env::{BindingEnv, Rule};
22use super::graph::{Edge, Node, EdgeIndex, NodeIndex, EdgeVisitMark};
23
24#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
25struct DelayedEdge(pub usize, pub EdgeIndex);
26
27/// A pool for delayed edges.
28/// Pools are scoped to a State. Edges within a State will share Pools. A Pool
29/// will keep a count of the total 'weight' of the currently scheduled edges. If
30/// a Plan attempts to schedule an Edge which would cause the total weight to
31/// exceed the depth of the Pool, the Pool will enque the Edge instead of
32/// allowing the Plan to schedule it. The Pool will relinquish queued Edges when
33/// the total scheduled weight diminishes enough (i.e. when a scheduled edge
34/// completes).
35pub struct Pool {
36 name: Vec<u8>,
37 /// |current_use_| is the total of the weights of the edges which are
38 /// currently scheduled in the Plan (i.e. the edges in Plan::ready_).
39 current_use: usize,
40 depth: usize,
41
42 delayed: BinaryHeap<DelayedEdge>,
43}
44
45impl Pool {
46 pub fn new(name: Vec<u8>, depth: usize) -> Self {
47 Pool {
48 name,
49 current_use: 0,
50 depth,
51 delayed: BinaryHeap::new(),
52 }
53 }
54
55 pub fn is_valid(&self) -> bool {
56 // A depth of 0 is infinite
57 self.depth >= 0
58 }
59
60 pub fn depth(&self) -> usize {
61 self.depth
62 }
63
64 pub fn name(&self) -> &[u8] {
65 &self.name
66 }
67
68 pub fn current_use(&self) -> usize {
69 self.current_use
70 }
71
72 /// true if the Pool might delay this edge
73 pub fn should_delay_edge(&self) -> bool {
74 self.depth != 0
75 }
76
77 /// adds the given edge to this Pool to be delayed.
78 pub fn delay_edge(&mut self, state: &State, edge: EdgeIndex) {
79 assert!(self.depth != 0);
80 self.delayed.push(DelayedEdge(
81 state.edge_state.get_edge(edge).weight(),
82 edge,
83 ));
84 }
85
86 /// Pool will add zero or more edges to the ready_queue
87 pub fn retrieve_ready_edges(&mut self, state: &State, ready_queue: &mut BTreeSet<EdgeIndex>) {
88 while let Some(DelayedEdge(weight, edge_index)) = self.delayed.peek().cloned() {
89 if self.current_use + weight > self.depth {
90 break;
91 }
92 self.delayed.pop();
93 ready_queue.insert(edge_index);
94 self.edge_scheduled(state, edge_index);
95 }
96 }
97
98 /// informs this Pool that the given edge is committed to be run.
99 /// Pool will count this edge as using resources from this pool.
100 pub fn edge_scheduled(&mut self, state: &State, edge: EdgeIndex) {
101 if self.depth != 0 {
102 self.current_use += state.edge_state.get_edge(edge).weight();
103 }
104 }
105
106 /// informs this Pool that the given edge is no longer runnable, and should
107 /// relinquish its resources back to the pool
108 pub fn edge_finished(&mut self, state: &State, edge: EdgeIndex) {
109 if self.depth != 0 {
110 self.current_use -= state.edge_state.get_edge(edge).weight();
111 }
112 }
113}
114
115/*
116
117struct Pool {
118 /// Dump the Pool and its edges (useful for debugging).
119 void Dump() const;
120};
121
122/// Global state (file status) for a single run.
123struct State {
124 static Pool kDefaultPool;
125 static Pool kConsolePool;
126 static const Rule kPhonyRule;
127
128 State();
129
130 void AddPool(Pool* pool);
131 Pool* LookupPool(const string& pool_name);
132
133 Edge* AddEdge(const Rule* rule);
134
135 Node* GetNode(StringPiece path, uint64_t slash_bits);
136 Node* LookupNode(StringPiece path) const;
137 Node* SpellcheckNode(const string& path);
138
139 void AddIn(Edge* edge, StringPiece path, uint64_t slash_bits);
140 bool AddOut(Edge* edge, StringPiece path, uint64_t slash_bits);
141 bool AddDefault(StringPiece path, string* error);
142
143 /// Dump the nodes and Pools (useful for debugging).
144 void Dump();
145
146 /// Mapping of path -> Node.
147 typedef ExternalStringHashMap<Node*>::Type Paths;
148 Paths paths_;
149
150 /// All the pools used in the graph.
151 map<string, Pool*> pools_;
152
153 /// All the edges of the graph.
154 vector<Edge*> edges_;
155
156 BindingEnv bindings_;
157 vector<Node*> defaults_;
158};
159
160#endif // NINJA_STATE_H_
161*/
162
163thread_local!{
164 pub static DEFAULT_POOL: Rc<RefCell<Pool>> =
165 Rc::new(RefCell::new(Pool::new(b"".as_ref().to_owned(), 0)));
166 pub static CONSOLE_POOL: Rc<RefCell<Pool>> =
167 Rc::new(RefCell::new(Pool::new(b"console".as_ref().to_owned(), 1)));
168
169 pub static PHONY_RULE: Rc<Rule> = Rc::new(Rule::new(b"phony".as_ref().to_owned()));
170}
171
172pub struct NodeState {
173 /// All the nodes of the graph.
174 nodes: Vec<Node>,
175
176 /// Mapping of path -> Node.
177 paths: HashMap<Vec<u8>, NodeIndex>,
178}
179
180impl NodeState {
181 pub fn new() -> Self {
182 NodeState {
183 nodes: Vec::new(),
184 paths: HashMap::new(),
185 }
186 }
187
188 pub fn prepare_node(&mut self, path: &[u8], slash_bits: u64) -> NodeIndex {
189 let node_idx = self.lookup_node(path);
190 if node_idx.is_some() {
191 return node_idx.unwrap();
192 }
193
194 let node = Node::new(path, slash_bits);
195 let node_idx = NodeIndex(self.nodes.len());
196 self.nodes.push(node);
197 self.paths.insert(path.to_owned(), node_idx);
198 node_idx
199 }
200
201 pub fn lookup_node(&self, path: &[u8]) -> Option<NodeIndex> {
202 metric_record!("lookup node");
203 self.paths.get(path).cloned()
204 }
205
206 pub fn get_node(&self, idx: NodeIndex) -> &Node {
207 self.nodes.get(idx.0).expect("index out of range")
208 }
209
210 pub fn get_node_mut(&mut self, idx: NodeIndex) -> &mut Node {
211 self.nodes.get_mut(idx.0).expect("index out of range")
212 }
213}
214
215pub struct EdgeState {
216 /// All the edges of the graph.
217 edges: Vec<Edge>,
218}
219
220impl EdgeState {
221 pub fn new() -> Self {
222 EdgeState { edges: Vec::new() }
223 }
224
225 pub fn len(&self) -> usize {
226 self.edges.len()
227 }
228
229 pub fn get_edge(&self, idx: EdgeIndex) -> &Edge {
230 self.edges.get(idx.0).expect("index out of range")
231 }
232
233 pub fn get_edge_mut(&mut self, idx: EdgeIndex) -> &mut Edge {
234 self.edges.get_mut(idx.0).expect("index out of range")
235 }
236
237 pub fn make_edge(&mut self, rule: Rc<Rule>, bindings: Rc<RefCell<BindingEnv>>) -> EdgeIndex {
238 let edge = Edge::new(rule, DEFAULT_POOL.with(Clone::clone), bindings);
239 let idx = EdgeIndex(self.edges.len());
240 self.edges.push(edge);
241 idx
242 }
243
244 pub fn revoke_latest_edge(&mut self, idx: EdgeIndex) {
245 if self.edges.len() != idx.0 + 1 {
246 panic!("trying to revoke an edge that is not the latest one.")
247 }
248 self.edges.pop();
249 }
250}
251
252pub struct PoolState {
253 /// All the pools used in the graph.
254 pools: HashMap<Vec<u8>, Rc<RefCell<Pool>>>,
255}
256
257impl PoolState {
258 pub fn new() -> Self {
259 PoolState { pools: HashMap::new() }
260 }
261
262 pub fn add_pool(&mut self, pool: Rc<RefCell<Pool>>) {
263 assert!(self.lookup_pool(pool.borrow().name()).is_none());
264 let name = pool.borrow().name().to_owned();
265 self.pools.insert(name, pool);
266 }
267
268 pub fn lookup_pool(&self, pool_name: &[u8]) -> Option<&Rc<RefCell<Pool>>> {
269 self.pools.get(pool_name)
270 }
271}
272
273/// Global state (file status) for a single run.
274pub struct State {
275 pub node_state: NodeState,
276 pub edge_state: EdgeState,
277 pub pool_state: PoolState,
278
279 pub bindings: Rc<RefCell<BindingEnv>>,
280 defaults: Option<Vec<NodeIndex>>,
281}
282
283impl State {
284 pub fn new() -> Self {
285 let mut state = State {
286 node_state: NodeState::new(),
287 edge_state: EdgeState::new(),
288 pool_state: PoolState::new(),
289 bindings: Rc::new(RefCell::new(BindingEnv::new())),
290 defaults: None,
291 };
292
293 state.bindings.borrow_mut().add_rule(
294 PHONY_RULE.with(Rc::clone),
295 );
296 state.pool_state.add_pool(DEFAULT_POOL.with(Rc::clone));
297 state.pool_state.add_pool(CONSOLE_POOL.with(Rc::clone));
298 state
299 }
300
301 pub fn connect_edge_to_in_node(
302 edge: &mut Edge,
303 edge_idx: EdgeIndex,
304 node: &mut Node,
305 node_idx: NodeIndex,
306 ) {
307 edge.inputs.push(node_idx);
308 node.add_out_edge(edge_idx);
309 }
310
311 pub fn connect_edge_to_out_node(
312 edge: &mut Edge,
313 edge_idx: EdgeIndex,
314 node: &mut Node,
315 node_idx: NodeIndex,
316 ) -> bool {
317 if node.in_edge().is_some() {
318 return false;
319 }
320 edge.outputs.push(node_idx);
321 node.set_in_edge(Some(edge_idx));
322 return true;
323 }
324
325 pub fn get_env(&self) -> Rc<RefCell<BindingEnv>> {
326 self.bindings.clone()
327 }
328
329 pub fn add_default(&mut self, path: &[u8]) -> Result<(), String> {
330 let node = self.node_state.lookup_node(path);
331 if let Some(node_idx) = node {
332 self.defaults.get_or_insert_with(Default::default).push(
333 node_idx,
334 );
335 Ok(())
336 } else {
337 Err(format!(
338 "unknown target '{}'",
339 String::from_utf8_lossy(path)
340 ))
341 }
342 }
343
344 /// @return the root node(s) of the graph. (Root nodes have no output edges).
345 /// @param error where to write the error message if somethings went wrong.
346 pub fn root_nodes(&self) -> Result<Vec<NodeIndex>, String> {
347 let mut root_nodes = Vec::new();
348 // Search for nodes with no output.
349 if !self.edge_state.edges.is_empty() {
350 for edge in self.edge_state.edges.iter() {
351 for out_idx in edge.outputs.iter().cloned() {
352 if self.node_state.get_node(out_idx).out_edges().is_empty() {
353 root_nodes.push(out_idx);
354 }
355 }
356 }
357 if root_nodes.is_empty() {
358 return Err("could not determine root nodes of build graph".to_owned());
359 }
360 }
361 return Ok(root_nodes);
362 }
363
364 pub fn default_nodes(&self) -> Result<Vec<NodeIndex>, String> {
365 if let Some(ref defaults) = self.defaults {
366 Ok(defaults.clone())
367 } else {
368 self.root_nodes()
369 }
370 }
371
372 /// Reset state. Keeps all nodes and edges, but restores them to the
373 /// state where we haven't yet examined the disk for dirty state.
374 pub fn reset(&mut self) {
375 for node in self.node_state.nodes.iter_mut() {
376 node.reset_state();
377 }
378
379 for edge in self.edge_state.edges.iter_mut() {
380 edge.outputs_ready = false;
381 edge.mark = EdgeVisitMark::VisitNone;
382 }
383 }
384
385 pub fn spellcheck_node(&self, path: &[u8]) -> Option<&[u8]> {
386 unimplemented!()
387 }
388}
389
390#[cfg(test)]
391impl State {
392 pub fn verify_graph(&self) {
393 for (i, e) in self.edge_state.edges.iter().enumerate() {
394 // All edges need at least one output.
395 assert_eq!(false, e.outputs.is_empty());
396
397 // Check that the edge's inputs have the edge as out-edge.
398 for in_node_idx in e.inputs.iter() {
399 let in_node = self.node_state.get_node(*in_node_idx);
400 assert!(in_node.out_edges().contains(&EdgeIndex(i)));
401 }
402
403 // Check that the edge's outputs have the edge as in-edge.
404 for out_node_idx in e.outputs.iter() {
405 let out_node = self.node_state.get_node(*out_node_idx);
406 assert_eq!(out_node.in_edge(), Some(EdgeIndex(i)));
407 }
408 }
409
410 // The union of all in- and out-edges of each nodes should be exactly edges_.
411 assert_eq!(self.node_state.paths.len(), self.node_state.nodes.len());
412 let mut node_edge_set = HashSet::new();
413 for n in self.node_state.nodes.iter() {
414 if let Some(in_edge) = n.in_edge() {
415 node_edge_set.insert(self.edge_state.get_edge(in_edge) as *const _);
416 }
417 node_edge_set.extend(n.out_edges().iter().map(|&r| {
418 self.edge_state.get_edge(r) as *const _
419 }));
420 }
421 let edge_set = self.edge_state
422 .edges
423 .iter()
424 .map(|r| r as *const _)
425 .collect::<HashSet<_>>();
426 assert_eq!(node_edge_set, edge_set);
427 }
428}
429
430
431/*
432// Copyright 2011 Google Inc. All Rights Reserved.
433//
434// Licensed under the Apache License, Version 2.0 (the "License");
435// you may not use this file except in compliance with the License.
436// You may obtain a copy of the License at
437//
438// http://www.apache.org/licenses/LICENSE-2.0
439//
440// Unless required by applicable law or agreed to in writing, software
441// distributed under the License is distributed on an "AS IS" BASIS,
442// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
443// See the License for the specific language governing permissions and
444// limitations under the License.
445
446#include "state.h"
447
448#include <assert.h>
449#include <stdio.h>
450
451#include "edit_distance.h"
452#include "graph.h"
453#include "metrics.h"
454#include "util.h"
455
456
457void Pool::EdgeScheduled(const Edge& edge) {
458 if (depth_ != 0)
459 current_use_ += edge.weight();
460}
461
462void Pool::EdgeFinished(const Edge& edge) {
463 if (depth_ != 0)
464 current_use_ -= edge.weight();
465}
466
467void Pool::RetrieveReadyEdges(set<Edge*>* ready_queue) {
468 DelayedEdges::iterator it = delayed_.begin();
469 while (it != delayed_.end()) {
470 Edge* edge = *it;
471 if (current_use_ + edge->weight() > depth_)
472 break;
473 ready_queue->insert(edge);
474 EdgeScheduled(*edge);
475 ++it;
476 }
477 delayed_.erase(delayed_.begin(), it);
478}
479
480void Pool::Dump() const {
481 printf("%s (%d/%d) ->\n", name_.c_str(), current_use_, depth_);
482 for (DelayedEdges::const_iterator it = delayed_.begin();
483 it != delayed_.end(); ++it)
484 {
485 printf("\t");
486 (*it)->Dump();
487 }
488}
489
490// static
491bool Pool::WeightedEdgeCmp(const Edge* a, const Edge* b) {
492 if (!a) return b;
493 if (!b) return false;
494 int weight_diff = a->weight() - b->weight();
495 return ((weight_diff < 0) || (weight_diff == 0 && a < b));
496}
497
498Edge* State::AddEdge(const Rule* rule) {
499 Edge* edge = new Edge();
500 edge->rule_ = rule;
501 edge->pool_ = &State::kDefaultPool;
502 edge->env_ = &bindings_;
503 edges_.push_back(edge);
504 return edge;
505}
506
507Node* State::SpellcheckNode(const string& path) {
508 const bool kAllowReplacements = true;
509 const int kMaxValidEditDistance = 3;
510
511 int min_distance = kMaxValidEditDistance + 1;
512 Node* result = NULL;
513 for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
514 int distance = EditDistance(
515 i->first, path, kAllowReplacements, kMaxValidEditDistance);
516 if (distance < min_distance && i->second) {
517 min_distance = distance;
518 result = i->second;
519 }
520 }
521 return result;
522}
523
524
525
526void State::Dump() {
527 for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
528 Node* node = i->second;
529 printf("%s %s [id:%d]\n",
530 node->path().c_str(),
531 node->status_known() ? (node->dirty() ? "dirty" : "clean")
532 : "unknown",
533 node->id());
534 }
535 if (!pools_.empty()) {
536 printf("resource_pools:\n");
537 for (map<string, Pool*>::const_iterator it = pools_.begin();
538 it != pools_.end(); ++it)
539 {
540 if (!it->second->name().empty()) {
541 it->second->Dump();
542 }
543 }
544 }
545}
546
547*/