Class: LVM::Snapshot

Inherits:
Object
  • Object
show all
Includes:
Helpers
Defined in:
lib/lvm/snapshot.rb

Instance Method Summary collapse

Methods included from Helpers

#big_endian?, #dtohq, #htonq, #ntohq, #swap_longs

Constructor Details

#initialize(vg, lv) ⇒ Snapshot

Returns a new instance of Snapshot.



9
10
11
12
# File 'lib/lvm/snapshot.rb', line 9

def initialize(vg, lv)
	@vg = vg
	@lv = lv
end

Instance Method Details

#differencesObject

Return an array of ranges which are the bytes which are different between the origin and the snapshot.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/lvm/snapshot.rb', line 16

def differences
	@differences ||= begin
		# For a regular, old-skool snapshot, getting the differences is
		# pretty trivial -- just read through the snapshot metadata, and
		# the list of changed blocks is right there.
		#
		diff_block_list = []

		File.open(, 'r') do |metafd|
			in_progress = true

			# The first chunk of the metadata LV is the header, which we
			# don't care for at all
			metafd.seek chunk_size, IO::SEEK_SET

			while in_progress
				# The snapshot on-disk format is a stream of <blocklist>, <blockdata>
				# sets; within each <blocklist>, it's little-endian 64-bit block
				# IDs -- the first is the location (chunk_size * offset) in the origin
				# LV that the data has been changed, the second is the location (again,
				# chunk_size * offset) in the metadata LV where the changed data is
				# being stored.
				(chunk_size / 16).times do
					origin_offset, snap_offset = metafd.read(16).unpack("QQ")
					origin_offset = dtohq(origin_offset)
					snap_offset   = dtohq(snap_offset)

					# A snapshot offset of 0 would point back to the metadata
					# device header, so that's clearly invalid -- hence it's the
					# "no more blocks" indicator.
					if snap_offset == 0
						in_progress = false
						break
					end

					diff_block_list << origin_offset
				end

				# We've read through a set of origin => data mappings; now we need
				# to take a giant leap over the data blocks that follow it.
				metafd.seek chunk_size * chunk_size / 16, IO::SEEK_CUR
			end
		end

		# Block-to-byte-range is pretty trivial, and we're done!
		diff_block_list.map do |b|
			((b*chunk_size)..(((b+1)*chunk_size)-1))
		end

		# There is one optimisation we could make here that we haven't --
		# coalescing adjacent byte ranges into single larger ranges.  I haven't
		# done it for two reasons: Firstly, I don't have any idea how much of a
		# real-world benefit it would be, and secondly, I couldn't work out how
		# to do it elegantly.  So I punted.
	end
end

#originObject



73
74
75
76
# File 'lib/lvm/snapshot.rb', line 73

def origin
	# Man old-skool snapshots are weird
	vgcfg.logical_volumes.values.find { |lv| lv.cow_store == @lv }.origin
end