lib/s3sync/sync.rb in s3sync-2.0.1 vs lib/s3sync/sync.rb in s3sync-2.0.2
- old
+ new
@@ -69,39 +69,44 @@
end
class Node
include Comparable
+ SMALL_FILE = 50 * 1024 # 50.kilobytes
+
attr_accessor :base
attr_accessor :path
attr_accessor :size
+ attr_accessor :small_comparator
- def initialize base, path, size
+ def initialize base, path, size, small_comparator = nil
@base = base
@path = path
@size = size
+ @small_comparator = small_comparator
end
def full
S3Sync.safe_join [@base, @path]
end
def == other
- full == other.full and @size == other.size
+ @size == other.size && compare_small_comparators(other)
end
- def <=> other
- if self.size < other.size
- -1
- elsif self.size > other.size
- 1
- else
- 0
- end
- end
-
alias eql? ==
+
+ private
+
+ # If files are small and both nodes have a comparator, we can call an extra
+ # provided block to verify equality. This allows
+ def compare_small_comparators(other)
+ return true if @size > SMALL_FILE || other.size > SMALL_FILE
+ return true if small_comparator.nil? || other.small_comparator.nil?
+
+ small_comparator.call == other.small_comparator.call
+ end
end
class LocalDirectory
attr_accessor :source
@@ -134,11 +139,12 @@
# folders and I don't think we care about any other thing, right?
next unless st.file?
# We only need the relative path here
file_name = file.gsub(/^#{@source}\/?/, '').squeeze('/')
- node = Node.new(@source.squeeze('/'), file_name, st.size)
+ small_comparator = lambda { Digest::MD5.hexdigest File.read(file) }
+ node = Node.new(@source.squeeze('/'), file_name, st.size, small_comparator)
nodes[node.path] = node
end
return nodes
end
@@ -151,11 +157,11 @@
hash1.each do |key, value|
value2 = hash2.delete key
if value2.nil?
to_add_to_2 << value
- elsif value2.size == value.size
+ elsif value2 == value
same << value
else
to_add_to_2 << value
end
end
@@ -295,10 +301,12 @@
dir = location.path
dir += '/' if not dir.empty? and not dir.end_with?('/')
nodes = {}
@args.s3.buckets[location.bucket].objects.with_prefix(dir || "").to_a.collect do |obj|
- node = Node.new(location.path, obj.key, obj.content_length)
+ # etag comes back with quotes (obj.etag.inspcet # => "\"abc...def\""
+ small_comparator = lambda { obj.etag[/[a-z0-9]+/] }
+ node = Node.new(location.path, obj.key, obj.content_length, small_comparator)
nodes[node.path] = node
end
return nodes
end