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

Side by Side Diff: extent_ranges.cc

Issue 3604005: AU: Ranges class to managing unordered collection of blocks/extents. (Closed) Base URL: ssh://git@chromiumos-git/update_engine.git
Patch Set: unittest whitespace fix Created 10 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
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // 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/extent_ranges.h"
6
7 #include <set>
8 #include <utility>
9 #include <vector>
10
11 #include <base/logging.h>
12
13 using std::max;
14 using std::min;
15 using std::set;
16 using std::vector;
17
18 namespace chromeos_update_engine {
19
20 bool ExtentRanges::ExtentsOverlapOrTouch(const Extent& a, const Extent& b) {
21 if (a.start_block() == b.start_block())
22 return true;
23 if (a.start_block() < b.start_block()) {
24 return a.start_block() + a.num_blocks() >= b.start_block();
25 } else {
26 return b.start_block() + b.num_blocks() >= a.start_block();
27 }
28 }
29
30 bool ExtentRanges::ExtentsOverlap(const Extent& a, const Extent& b) {
31 if (a.start_block() == b.start_block())
32 return true;
33 if (a.start_block() < b.start_block()) {
34 return a.start_block() + a.num_blocks() > b.start_block();
35 } else {
36 return b.start_block() + b.num_blocks() > a.start_block();
37 }
38 }
39
40 void ExtentRanges::AddBlock(uint64_t block) {
41 AddExtent(ExtentForRange(block, 1));
42 }
43
44 void ExtentRanges::SubtractBlock(uint64_t block) {
45 SubtractExtent(ExtentForRange(block, 1));
46 }
47
48 namespace {
49
50 Extent UnionOverlappingExtents(const Extent& first, const Extent& second) {
51 uint64_t start = min(first.start_block(), second.start_block());
52 uint64_t end = max(first.start_block() + first.num_blocks(),
53 second.start_block() + second.num_blocks());
54 return ExtentForRange(start, end - start);
55 }
56
57 } // namespace {}
58
59 void ExtentRanges::AddExtent(Extent extent) {
60 if (extent.num_blocks() == 0)
61 return;
62
63 ExtentSet::iterator begin_del = extent_set_.end();
64 ExtentSet::iterator end_del = extent_set_.end();
65 uint64_t del_blocks = 0;
66 for (ExtentSet::iterator it = extent_set_.begin(), e = extent_set_.end();
67 it != e; ++it) {
68 if (ExtentsOverlapOrTouch(*it, extent)) {
69 end_del = it;
70 ++end_del;
71 del_blocks += it->num_blocks();
72 if (begin_del == extent_set_.end())
73 begin_del = it;
74
75 extent = UnionOverlappingExtents(extent, *it);
76 }
77 }
78 extent_set_.erase(begin_del, end_del);
79 extent_set_.insert(extent);
80 blocks_ -= del_blocks;
81 blocks_ += extent.num_blocks();
82 }
83
84 namespace {
85 // Returns base - subtractee (set subtraction).
86 ExtentRanges::ExtentSet SubtractOverlappingExtents(const Extent& base,
87 const Extent& subtractee) {
88 ExtentRanges::ExtentSet ret;
89 if (subtractee.start_block() > base.start_block()) {
90 ret.insert(ExtentForRange(base.start_block(),
91 subtractee.start_block() - base.start_block()));
92 }
93 uint64_t base_end = base.start_block() + base.num_blocks();
94 uint64_t subtractee_end = subtractee.start_block() + subtractee.num_blocks();
95 if (base_end > subtractee_end) {
96 ret.insert(ExtentForRange(subtractee_end, base_end - subtractee_end));
97 }
98 return ret;
99 }
100 } // namespace {}
101
102 void ExtentRanges::SubtractExtent(const Extent& extent) {
103 if (extent.num_blocks() == 0)
104 return;
105
106 ExtentSet::iterator begin_del = extent_set_.end();
107 ExtentSet::iterator end_del = extent_set_.end();
108 uint64_t del_blocks = 0;
109 ExtentSet new_extents;
110 for (ExtentSet::iterator it = extent_set_.begin(), e = extent_set_.end();
111 it != e; ++it) {
112 if (!ExtentsOverlap(*it, extent))
113 continue;
114
115 if (begin_del == extent_set_.end())
116 begin_del = it;
117 end_del = it;
118 ++end_del;
119
120 del_blocks += it->num_blocks();
121
122 ExtentSet subtraction = SubtractOverlappingExtents(*it, extent);
123 for (ExtentSet::iterator jt = subtraction.begin(), je = subtraction.end();
124 jt != je; ++jt) {
125 new_extents.insert(*jt);
126 del_blocks -= jt->num_blocks();
127 }
128 }
129 extent_set_.erase(begin_del, end_del);
130 extent_set_.insert(new_extents.begin(), new_extents.end());
131 blocks_ -= del_blocks;
132 }
133
134 void ExtentRanges::AddRanges(const ExtentRanges& ranges) {
135 for (ExtentSet::const_iterator it = ranges.extent_set_.begin(),
136 e = ranges.extent_set_.end(); it != e; ++it) {
137 AddExtent(*it);
138 }
139 }
140
141 void ExtentRanges::SubtractRanges(const ExtentRanges& ranges) {
142 for (ExtentSet::const_iterator it = ranges.extent_set_.begin(),
143 e = ranges.extent_set_.end(); it != e; ++it) {
144 SubtractExtent(*it);
145 }
146 }
147
148 void ExtentRanges::AddExtents(const vector<Extent>& extents) {
149 for (vector<Extent>::const_iterator it = extents.begin(), e = extents.end();
150 it != e; ++it) {
151 AddExtent(*it);
152 }
153 }
154
155 void ExtentRanges::SubtractExtents(const vector<Extent>& extents) {
156 for (vector<Extent>::const_iterator it = extents.begin(), e = extents.end();
157 it != e; ++it) {
158 SubtractExtent(*it);
159 }
160 }
161
162 void ExtentRanges::AddRepeatedExtents(
163 const ::google::protobuf::RepeatedPtrField<Extent> &exts) {
164 for (int i = 0, e = exts.size(); i != e; ++i) {
165 AddExtent(exts.Get(i));
166 }
167 }
168
169 void ExtentRanges::SubtractRepeatedExtents(
170 const ::google::protobuf::RepeatedPtrField<Extent> &exts) {
171 for (int i = 0, e = exts.size(); i != e; ++i) {
172 SubtractExtent(exts.Get(i));
173 }
174 }
175
176 void ExtentRanges::Dump() const {
177 LOG(INFO) << "ExtentRanges Dump. blocks: " << blocks_;
178 for (ExtentSet::const_iterator it = extent_set_.begin(),
179 e = extent_set_.end();
180 it != e; ++it) {
181 LOG(INFO) << "{" << it->start_block() << ", " << it->num_blocks() << "}";
182 }
183 }
184
185 Extent ExtentForRange(uint64_t start_block, uint64_t num_blocks) {
186 Extent ret;
187 ret.set_start_block(start_block);
188 ret.set_num_blocks(num_blocks);
189 return ret;
190 }
191
192 std::vector<Extent> ExtentRanges::GetExtentsForBlockCount(
193 uint64_t count) const {
194 vector<Extent> out;
195 if (count == 0)
196 return out;
197 uint64_t out_blocks = 0;
198 CHECK(count <= blocks_);
199 for (ExtentSet::const_iterator it = extent_set_.begin(),
200 e = extent_set_.end();
201 it != e; ++it) {
202 const uint64_t blocks_needed = count - out_blocks;
203 const Extent& extent = *it;
204 out.push_back(extent);
205 out_blocks += extent.num_blocks();
206 if (extent.num_blocks() < blocks_needed)
207 continue;
208 if (extent.num_blocks() == blocks_needed)
209 break;
210 // If we get here, we just added the last extent needed, but it's too big
211 out_blocks -= extent.num_blocks();
212 out_blocks += blocks_needed;
213 out.back().set_num_blocks(blocks_needed);
214 break;
215 }
216 return out;
217 }
218
219 } // namespace chromeos_update_engine
OLDNEW
« extent_ranges.h ('K') | « extent_ranges.h ('k') | extent_ranges_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698