blob: 3e3cc9e4b73a0beea54f515a5b9306ca7eaf7a72 [file] [log] [blame]
Darin Petkov8e447e02013-04-16 16:23:50 +02001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -08002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/graph_utils.h"
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -08006
Andrew de los Reyes1bc16ab2010-10-06 15:07:21 -07007#include <string>
8#include <utility>
9#include <vector>
10
11#include <base/basictypes.h>
12#include <base/logging.h>
13
14using std::make_pair;
15using std::pair;
16using std::string;
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -080017using std::vector;
18
19namespace chromeos_update_engine {
20
21namespace graph_utils {
22
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070023uint64_t EdgeWeight(const Graph& graph, const Edge& edge) {
24 uint64_t weight = 0;
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -080025 const vector<Extent>& extents =
26 graph[edge.first].out_edges.find(edge.second)->second.extents;
27 for (vector<Extent>::const_iterator it = extents.begin();
28 it != extents.end(); ++it) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070029 if (it->start_block() != kSparseHole)
30 weight += it->num_blocks();
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -080031 }
32 return weight;
33}
34
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070035void AppendBlockToExtents(vector<Extent>* extents, uint64_t block) {
Darin Petkov94817cb2013-05-08 14:33:24 +020036 // First try to extend the last extent in |extents|, if any.
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -080037 if (!extents->empty()) {
38 Extent& extent = extents->back();
Darin Petkov94817cb2013-05-08 14:33:24 +020039 uint64_t next_block = extent.start_block() == kSparseHole ?
40 kSparseHole : extent.start_block() + extent.num_blocks();
41 if (next_block == block) {
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -080042 extent.set_num_blocks(extent.num_blocks() + 1);
43 return;
44 }
45 }
Darin Petkov94817cb2013-05-08 14:33:24 +020046 // If unable to extend the last extent, append a new single-block extent.
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -080047 Extent new_extent;
48 new_extent.set_start_block(block);
49 new_extent.set_num_blocks(1);
50 extents->push_back(new_extent);
51}
52
Andrew de los Reyes1bc16ab2010-10-06 15:07:21 -070053void AddReadBeforeDep(Vertex* src,
54 Vertex::Index dst,
55 uint64_t block) {
56 Vertex::EdgeMap::iterator edge_it = src->out_edges.find(dst);
57 if (edge_it == src->out_edges.end()) {
58 // Must create new edge
59 pair<Vertex::EdgeMap::iterator, bool> result =
60 src->out_edges.insert(make_pair(dst, EdgeProperties()));
61 CHECK(result.second);
62 edge_it = result.first;
63 }
64 AppendBlockToExtents(&edge_it->second.extents, block);
65}
66
67void AddReadBeforeDepExtents(Vertex* src,
68 Vertex::Index dst,
69 const vector<Extent>& extents) {
70 // TODO(adlr): Be more efficient than adding each block individually.
71 for (vector<Extent>::const_iterator it = extents.begin(), e = extents.end();
72 it != e; ++it) {
73 const Extent& extent = *it;
74 for (uint64_t block = extent.start_block(),
75 block_end = extent.start_block() + extent.num_blocks();
76 block != block_end; ++block) {
77 AddReadBeforeDep(src, dst, block);
78 }
79 }
80}
81
82void DropWriteBeforeDeps(Vertex::EdgeMap* edge_map) {
83 // Specially crafted for-loop for the map-iterate-delete dance.
84 for (Vertex::EdgeMap::iterator it = edge_map->begin();
85 it != edge_map->end(); ) {
86 if (!it->second.write_extents.empty())
87 it->second.write_extents.clear();
88 if (it->second.extents.empty()) {
89 // Erase *it, as it contains no blocks
90 edge_map->erase(it++);
91 } else {
92 ++it;
93 }
94 }
95}
96
97// For each node N in graph, drop all edges N->|index|.
98void DropIncomingEdgesTo(Graph* graph, Vertex::Index index) {
99 // This would be much more efficient if we had doubly-linked
100 // edges in the graph.
101 for (Graph::iterator it = graph->begin(), e = graph->end(); it != e; ++it) {
102 it->out_edges.erase(index);
103 }
104}
105
106Extent GetElement(const std::vector<Extent>& collection, size_t index) {
107 return collection[index];
108}
109Extent GetElement(
110 const google::protobuf::RepeatedPtrField<Extent>& collection,
111 size_t index) {
112 return collection.Get(index);
113}
114
115namespace {
116template<typename T>
117void DumpExtents(const T& field, int prepend_space_count) {
118 string header(prepend_space_count, ' ');
119 for (int i = 0, e = field.size(); i != e; ++i) {
120 LOG(INFO) << header << "(" << GetElement(field, i).start_block() << ", "
121 << GetElement(field, i).num_blocks() << ")";
122 }
123}
124
125void DumpOutEdges(const Vertex::EdgeMap& out_edges) {
126 for (Vertex::EdgeMap::const_iterator it = out_edges.begin(),
127 e = out_edges.end(); it != e; ++it) {
128 LOG(INFO) << " " << it->first << " read-before:";
129 DumpExtents(it->second.extents, 6);
130 LOG(INFO) << " write-before:";
131 DumpExtents(it->second.write_extents, 6);
132 }
133}
134} // namespace {}
135
136void DumpGraph(const Graph& graph) {
137 LOG(INFO) << "Graph length: " << graph.size();
138 for (Graph::size_type i = 0, e = graph.size(); i != e; ++i) {
139 string type_str = "UNK";
140 switch(graph[i].op.type()) {
141 case DeltaArchiveManifest_InstallOperation_Type_BSDIFF:
142 type_str = "BSDIFF";
143 break;
144 case DeltaArchiveManifest_InstallOperation_Type_MOVE:
145 type_str = "MOVE";
146 break;
147 case DeltaArchiveManifest_InstallOperation_Type_REPLACE:
148 type_str = "REPLACE";
149 break;
150 case DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ:
151 type_str = "REPLACE_BZ";
152 break;
153 }
Darin Petkov8e447e02013-04-16 16:23:50 +0200154 LOG(INFO) << i
Andrew de los Reyes1bc16ab2010-10-06 15:07:21 -0700155 << (graph[i].valid ? "" : "-INV")
156 << ": " << graph[i].file_name
Darin Petkov8e447e02013-04-16 16:23:50 +0200157 << " " << graph[i].chunk_size << "@" << graph[i].chunk_offset
Andrew de los Reyes1bc16ab2010-10-06 15:07:21 -0700158 << ": " << type_str;
159 LOG(INFO) << " src_extents:";
160 DumpExtents(graph[i].op.src_extents(), 4);
161 LOG(INFO) << " dst_extents:";
162 DumpExtents(graph[i].op.dst_extents(), 4);
163 LOG(INFO) << " out edges:";
164 DumpOutEdges(graph[i].out_edges);
165 }
166}
167
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -0800168} // namespace graph_utils
169
Andrew de los Reyes1bc16ab2010-10-06 15:07:21 -0700170bool operator==(const Extent& a, const Extent& b) {
171 return a.start_block() == b.start_block() && a.num_blocks() == b.num_blocks();
172}
173
Andrew de los Reyes0ce161b2010-02-22 15:27:01 -0800174} // namespace chromeos_update_engine