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*/