Class: LVM::Snapshot
Instance Method Summary collapse
-
#differences ⇒ Object
Return an array of ranges which are the bytes which are different between the origin and the snapshot.
-
#initialize(vg, lv) ⇒ Snapshot
constructor
A new instance of Snapshot.
- #origin ⇒ Object
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
#differences ⇒ Object
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 || in_progress = true # The first chunk of the metadata LV is the header, which we # don't care for at all .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 = .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. .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 |
#origin ⇒ Object
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 |