| Index: extent_ranges.cc
|
| diff --git a/extent_ranges.cc b/extent_ranges.cc
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..a8836c9e5639bedc467af58f59e971f2c60b1dfc
|
| --- /dev/null
|
| +++ b/extent_ranges.cc
|
| @@ -0,0 +1,219 @@
|
| +// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "update_engine/extent_ranges.h"
|
| +
|
| +#include <set>
|
| +#include <utility>
|
| +#include <vector>
|
| +
|
| +#include <base/logging.h>
|
| +
|
| +using std::max;
|
| +using std::min;
|
| +using std::set;
|
| +using std::vector;
|
| +
|
| +namespace chromeos_update_engine {
|
| +
|
| +bool ExtentRanges::ExtentsOverlapOrTouch(const Extent& a, const Extent& b) {
|
| + if (a.start_block() == b.start_block())
|
| + return true;
|
| + if (a.start_block() < b.start_block()) {
|
| + return a.start_block() + a.num_blocks() >= b.start_block();
|
| + } else {
|
| + return b.start_block() + b.num_blocks() >= a.start_block();
|
| + }
|
| +}
|
| +
|
| +bool ExtentRanges::ExtentsOverlap(const Extent& a, const Extent& b) {
|
| + if (a.start_block() == b.start_block())
|
| + return true;
|
| + if (a.start_block() < b.start_block()) {
|
| + return a.start_block() + a.num_blocks() > b.start_block();
|
| + } else {
|
| + return b.start_block() + b.num_blocks() > a.start_block();
|
| + }
|
| +}
|
| +
|
| +void ExtentRanges::AddBlock(uint64_t block) {
|
| + AddExtent(ExtentForRange(block, 1));
|
| +}
|
| +
|
| +void ExtentRanges::SubtractBlock(uint64_t block) {
|
| + SubtractExtent(ExtentForRange(block, 1));
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +Extent UnionOverlappingExtents(const Extent& first, const Extent& second) {
|
| + uint64_t start = min(first.start_block(), second.start_block());
|
| + uint64_t end = max(first.start_block() + first.num_blocks(),
|
| + second.start_block() + second.num_blocks());
|
| + return ExtentForRange(start, end - start);
|
| +}
|
| +
|
| +} // namespace {}
|
| +
|
| +void ExtentRanges::AddExtent(Extent extent) {
|
| + if (extent.num_blocks() == 0)
|
| + return;
|
| +
|
| + ExtentSet::iterator begin_del = extent_set_.end();
|
| + ExtentSet::iterator end_del = extent_set_.end();
|
| + uint64_t del_blocks = 0;
|
| + for (ExtentSet::iterator it = extent_set_.begin(), e = extent_set_.end();
|
| + it != e; ++it) {
|
| + if (ExtentsOverlapOrTouch(*it, extent)) {
|
| + end_del = it;
|
| + ++end_del;
|
| + del_blocks += it->num_blocks();
|
| + if (begin_del == extent_set_.end())
|
| + begin_del = it;
|
| +
|
| + extent = UnionOverlappingExtents(extent, *it);
|
| + }
|
| + }
|
| + extent_set_.erase(begin_del, end_del);
|
| + extent_set_.insert(extent);
|
| + blocks_ -= del_blocks;
|
| + blocks_ += extent.num_blocks();
|
| +}
|
| +
|
| +namespace {
|
| +// Returns base - subtractee (set subtraction).
|
| +ExtentRanges::ExtentSet SubtractOverlappingExtents(const Extent& base,
|
| + const Extent& subtractee) {
|
| + ExtentRanges::ExtentSet ret;
|
| + if (subtractee.start_block() > base.start_block()) {
|
| + ret.insert(ExtentForRange(base.start_block(),
|
| + subtractee.start_block() - base.start_block()));
|
| + }
|
| + uint64_t base_end = base.start_block() + base.num_blocks();
|
| + uint64_t subtractee_end = subtractee.start_block() + subtractee.num_blocks();
|
| + if (base_end > subtractee_end) {
|
| + ret.insert(ExtentForRange(subtractee_end, base_end - subtractee_end));
|
| + }
|
| + return ret;
|
| +}
|
| +} // namespace {}
|
| +
|
| +void ExtentRanges::SubtractExtent(const Extent& extent) {
|
| + if (extent.num_blocks() == 0)
|
| + return;
|
| +
|
| + ExtentSet::iterator begin_del = extent_set_.end();
|
| + ExtentSet::iterator end_del = extent_set_.end();
|
| + uint64_t del_blocks = 0;
|
| + ExtentSet new_extents;
|
| + for (ExtentSet::iterator it = extent_set_.begin(), e = extent_set_.end();
|
| + it != e; ++it) {
|
| + if (!ExtentsOverlap(*it, extent))
|
| + continue;
|
| +
|
| + if (begin_del == extent_set_.end())
|
| + begin_del = it;
|
| + end_del = it;
|
| + ++end_del;
|
| +
|
| + del_blocks += it->num_blocks();
|
| +
|
| + ExtentSet subtraction = SubtractOverlappingExtents(*it, extent);
|
| + for (ExtentSet::iterator jt = subtraction.begin(), je = subtraction.end();
|
| + jt != je; ++jt) {
|
| + new_extents.insert(*jt);
|
| + del_blocks -= jt->num_blocks();
|
| + }
|
| + }
|
| + extent_set_.erase(begin_del, end_del);
|
| + extent_set_.insert(new_extents.begin(), new_extents.end());
|
| + blocks_ -= del_blocks;
|
| +}
|
| +
|
| +void ExtentRanges::AddRanges(const ExtentRanges& ranges) {
|
| + for (ExtentSet::const_iterator it = ranges.extent_set_.begin(),
|
| + e = ranges.extent_set_.end(); it != e; ++it) {
|
| + AddExtent(*it);
|
| + }
|
| +}
|
| +
|
| +void ExtentRanges::SubtractRanges(const ExtentRanges& ranges) {
|
| + for (ExtentSet::const_iterator it = ranges.extent_set_.begin(),
|
| + e = ranges.extent_set_.end(); it != e; ++it) {
|
| + SubtractExtent(*it);
|
| + }
|
| +}
|
| +
|
| +void ExtentRanges::AddExtents(const vector<Extent>& extents) {
|
| + for (vector<Extent>::const_iterator it = extents.begin(), e = extents.end();
|
| + it != e; ++it) {
|
| + AddExtent(*it);
|
| + }
|
| +}
|
| +
|
| +void ExtentRanges::SubtractExtents(const vector<Extent>& extents) {
|
| + for (vector<Extent>::const_iterator it = extents.begin(), e = extents.end();
|
| + it != e; ++it) {
|
| + SubtractExtent(*it);
|
| + }
|
| +}
|
| +
|
| +void ExtentRanges::AddRepeatedExtents(
|
| + const ::google::protobuf::RepeatedPtrField<Extent> &exts) {
|
| + for (int i = 0, e = exts.size(); i != e; ++i) {
|
| + AddExtent(exts.Get(i));
|
| + }
|
| +}
|
| +
|
| +void ExtentRanges::SubtractRepeatedExtents(
|
| + const ::google::protobuf::RepeatedPtrField<Extent> &exts) {
|
| + for (int i = 0, e = exts.size(); i != e; ++i) {
|
| + SubtractExtent(exts.Get(i));
|
| + }
|
| +}
|
| +
|
| +void ExtentRanges::Dump() const {
|
| + LOG(INFO) << "ExtentRanges Dump. blocks: " << blocks_;
|
| + for (ExtentSet::const_iterator it = extent_set_.begin(),
|
| + e = extent_set_.end();
|
| + it != e; ++it) {
|
| + LOG(INFO) << "{" << it->start_block() << ", " << it->num_blocks() << "}";
|
| + }
|
| +}
|
| +
|
| +Extent ExtentForRange(uint64_t start_block, uint64_t num_blocks) {
|
| + Extent ret;
|
| + ret.set_start_block(start_block);
|
| + ret.set_num_blocks(num_blocks);
|
| + return ret;
|
| +}
|
| +
|
| +std::vector<Extent> ExtentRanges::GetExtentsForBlockCount(
|
| + uint64_t count) const {
|
| + vector<Extent> out;
|
| + if (count == 0)
|
| + return out;
|
| + uint64_t out_blocks = 0;
|
| + CHECK(count <= blocks_);
|
| + for (ExtentSet::const_iterator it = extent_set_.begin(),
|
| + e = extent_set_.end();
|
| + it != e; ++it) {
|
| + const uint64_t blocks_needed = count - out_blocks;
|
| + const Extent& extent = *it;
|
| + out.push_back(extent);
|
| + out_blocks += extent.num_blocks();
|
| + if (extent.num_blocks() < blocks_needed)
|
| + continue;
|
| + if (extent.num_blocks() == blocks_needed)
|
| + break;
|
| + // If we get here, we just added the last extent needed, but it's too big
|
| + out_blocks -= extent.num_blocks();
|
| + out_blocks += blocks_needed;
|
| + out.back().set_num_blocks(blocks_needed);
|
| + break;
|
| + }
|
| + return out;
|
| +}
|
| +
|
| +} // namespace chromeos_update_engine
|
|
|