AU: Delta Performer: properly detect idempotent operations

Idempotent operations can be restarted after being aborted. This CL
enables the delta performer to find many idempotent operations. The
algorithm given is pretty good, tho it may incorrectly mark some
idempotent operations as non-idempotent. For example, a BSDIFF
operation may write a block that it reads with the same data; that's
idempotent, but missed by this algorithm. This function just looks to
see if the src/dst blocks are non-intersecting and, if non
intersecting, declares it idempotent.

BUG=7394
TEST=unittest

Review URL: http://codereview.chromium.org/3591019
diff --git a/delta_performer.cc b/delta_performer.cc
index 0eccb09..9bf3d34 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -18,6 +18,7 @@
 
 #include "update_engine/bzip_extent_writer.h"
 #include "update_engine/delta_diff_generator.h"
+#include "update_engine/extent_ranges.h"
 #include "update_engine/extent_writer.h"
 #include "update_engine/graph_types.h"
 #include "update_engine/payload_signer.h"
@@ -40,17 +41,6 @@
     "/usr/share/update_engine/update-payload-key.pub.pem";
 const int kUpdateStateOperationInvalid = -1;
 
-// Returns true if |op| is idempotent -- i.e., if we can interrupt it and repeat
-// it safely. Returns false otherwise.
-bool IsIdempotentOperation(const DeltaArchiveManifest_InstallOperation& op) {
-  if (op.src_extents_size() == 0) {
-    return true;
-  }
-  // TODO(petkov): Cover the case where the source and target extents don't
-  // intersect.
-  return false;
-}
-
 // Converts extents to a human-readable string, for use by DumpUpdateProto().
 string ExtentsToString(const RepeatedPtrField<Extent>& extents) {
   string ret;
@@ -121,6 +111,24 @@
 
 }  // namespace {}
 
+// Returns true if |op| is idempotent -- i.e., if we can interrupt it and repeat
+// it safely. Returns false otherwise.
+bool DeltaPerformer::IsIdempotentOperation(
+    const DeltaArchiveManifest_InstallOperation& op) {
+  if (op.src_extents_size() == 0) {
+    return true;
+  }
+  // TODO(adlr): detect other types of idempotent operations. For example,
+  // a MOVE may move a block onto itself.
+
+  // When in doubt, it's safe to declare an op non-idempotent.
+  ExtentRanges src_ranges;
+  src_ranges.AddRepeatedExtents(op.src_extents());
+  const uint64_t block_count = src_ranges.blocks();
+  src_ranges.SubtractRepeatedExtents(op.dst_extents());
+  return block_count == src_ranges.blocks();
+}
+
 int DeltaPerformer::Open(const char* path, int flags, mode_t mode) {
   int err;
   if (OpenFile(path, &fd_, &err))