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