thinp_xml 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/.rspec +2 -0
- data/bin/cache_xml +125 -0
- data/bin/thinp_xml +5 -8
- data/features/cache_create.feature +65 -0
- data/features/cache_usage.feature +17 -0
- data/features/step_definitions/thinp_xml.rb +4 -0
- data/features/{create.feature → thinp_create.feature} +0 -0
- data/features/{usage.feature → thinp_usage.feature} +0 -0
- data/lib/thinp_xml/cache/builder.rb +92 -0
- data/lib/thinp_xml/cache/emit.rb +43 -0
- data/lib/thinp_xml/cache/metadata.rb +22 -0
- data/lib/thinp_xml/cache/parse.rb +53 -0
- data/lib/thinp_xml/cache_xml.rb +5 -0
- data/lib/thinp_xml/distribution.rb +25 -3
- data/lib/thinp_xml/emitter.rb +40 -0
- data/lib/thinp_xml/listener.rb +51 -0
- data/lib/thinp_xml/{analysis.rb → thinp/analysis.rb} +0 -0
- data/lib/thinp_xml/{builder.rb → thinp/builder.rb} +1 -1
- data/lib/thinp_xml/thinp/emit.rb +48 -0
- data/lib/thinp_xml/{metadata.rb → thinp/metadata.rb} +0 -0
- data/lib/thinp_xml/{parse.rb → thinp/parse.rb} +7 -33
- data/lib/thinp_xml/{utils.rb → thinp/utils.rb} +1 -1
- data/lib/thinp_xml/{xml_format.rb → thinp/xml_format.rb} +0 -0
- data/lib/thinp_xml/version.rb +1 -1
- data/lib/thinp_xml.rb +5 -5
- data/spec/builder_spec.rb +1 -1
- data/spec/cache_builder_spec.rb +240 -0
- data/spec/distribution_spec.rb +87 -1
- metadata +29 -13
- data/lib/thinp_xml/emit.rb +0 -69
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTdjOGQ5NDUyYzJiYzY2MzExMjU4MzhjNWZkMjg5MzcyOTVlZDU1ZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ODNkZmU4YzE2OTQxZThjYmFlZjkxZTZjOTdkMTBhOWYyOTgwNmY0Mw==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZWI5OWZjNTEzZjUyYzQ5YzM1YTViYmIxMzcyMjZjYTg1ZDU4MzYyNjc3MzI4
|
10
|
+
NTAwNDU4ZjYzMGNhOGU2Njg0MWYzZjQxZWU1OWUyYjhmZTBkYWY4YzBjMjNh
|
11
|
+
ODJmNzAxMmYyOWY4ZDVjYTEwMTZkMGU5NGJkMWIzY2U0ZGE1MGM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NTNlOGY3NDU4MWYzYWY3YjViNjJkYjE5ZTNiMmM2Y2NkZmM5NGYwMTdhZjRj
|
14
|
+
NzdjMTI1NjM1NWU1ZDI3ODU3ZjkxZGYzZGUyN2RlMjMwNmM3YTg4Mjg3NWQ4
|
15
|
+
NDBkYWZlMjA5NmU3MmFhOGE3Nzk2NzZlNGM0YTljOTZjNTgwMzc=
|
data/.rspec
ADDED
data/bin/cache_xml
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'thinp_xml/cache_xml'
|
4
|
+
require 'thinp_xml/distribution'
|
5
|
+
require 'ejt_command_line'
|
6
|
+
|
7
|
+
include ThinpXML
|
8
|
+
|
9
|
+
#----------------------------------------------------------------
|
10
|
+
|
11
|
+
CacheCommandLine = CommandLine::Parser.new do
|
12
|
+
value_type :string do |str|
|
13
|
+
str
|
14
|
+
end
|
15
|
+
|
16
|
+
value_type :int do |str|
|
17
|
+
Integer(str)
|
18
|
+
end
|
19
|
+
|
20
|
+
value_type :distribution do |str|
|
21
|
+
parse_distribution(str)
|
22
|
+
end
|
23
|
+
|
24
|
+
value_type :layout do |str|
|
25
|
+
case str
|
26
|
+
when 'random'
|
27
|
+
:random
|
28
|
+
|
29
|
+
when 'linear'
|
30
|
+
:linear
|
31
|
+
|
32
|
+
else
|
33
|
+
raise "unknown mapping layout '#{str}'"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
value_type :percentage do |str|
|
38
|
+
i = Integer(str)
|
39
|
+
raise "invalid percentage value (#{i})" if i < 0 || i > 100
|
40
|
+
i
|
41
|
+
end
|
42
|
+
|
43
|
+
simple_switch :help, '--help', '-h'
|
44
|
+
value_switch :uuid, :string, '--uuid'
|
45
|
+
value_switch :block_size, :int, '--block-size'
|
46
|
+
value_switch :nr_cache_blocks, :distribution, '--nr-cache-blocks'
|
47
|
+
value_switch :nr_mappings, :distribution, '--nr-mappings'
|
48
|
+
value_switch :mapping_policy, :layout, '--layout'
|
49
|
+
value_switch :dirty_percentage, :percentage, '--dirty-percent'
|
50
|
+
|
51
|
+
global do
|
52
|
+
switches :help
|
53
|
+
end
|
54
|
+
|
55
|
+
command :create do
|
56
|
+
switches :nr_cache_blocks, :uuid, :block_size, :nr_mappings, :mapping_policy, :dirty_percentage
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
#--------------------------------
|
61
|
+
|
62
|
+
class Dispatcher
|
63
|
+
include CacheXML
|
64
|
+
|
65
|
+
def global_command(opts, args)
|
66
|
+
if args.size > 0
|
67
|
+
die "unknown command '#{args[0]}'"
|
68
|
+
else
|
69
|
+
if opts[:help]
|
70
|
+
help(STDOUT)
|
71
|
+
else
|
72
|
+
die "no command given"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def create(opts, args)
|
78
|
+
b = Builder.new
|
79
|
+
b.uuid = opts.fetch(:uuid, '')
|
80
|
+
b.nr_cache_blocks = opts.fetch(:nr_cache_blocks, 0).to_i
|
81
|
+
b.block_size = opts.fetch(:block_size, 128)
|
82
|
+
b.nr_mappings = opts.fetch(:nr_mappings, 0)
|
83
|
+
b.mapping_policy = opts.fetch(:mapping_policy, :random)
|
84
|
+
b.dirty_percentage = opts.fetch(:dirty_percentage, 0)
|
85
|
+
md = b.generate
|
86
|
+
write_xml(md, STDOUT)
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
def die(msg)
|
91
|
+
STDERR.puts msg
|
92
|
+
exit(1)
|
93
|
+
end
|
94
|
+
|
95
|
+
def help(out)
|
96
|
+
out.write <<EOF
|
97
|
+
Manipulation of cache xml format metadata
|
98
|
+
--help, -h: Show this message
|
99
|
+
EOF
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def parse_command_line(dispatcher, *args)
|
104
|
+
CacheCommandLine.parse(dispatcher, *args)
|
105
|
+
end
|
106
|
+
|
107
|
+
def top_level_handler(&block)
|
108
|
+
begin
|
109
|
+
block.call
|
110
|
+
rescue => e
|
111
|
+
STDERR.puts e.message
|
112
|
+
exit 1
|
113
|
+
end
|
114
|
+
|
115
|
+
exit 0
|
116
|
+
end
|
117
|
+
|
118
|
+
#----------------------------------------------------------------
|
119
|
+
|
120
|
+
top_level_handler do
|
121
|
+
dispatcher = Dispatcher.new
|
122
|
+
parse_command_line(dispatcher, *ARGV)
|
123
|
+
end
|
124
|
+
|
125
|
+
#----------------------------------------------------------------
|
data/bin/thinp_xml
CHANGED
@@ -4,6 +4,8 @@ require 'thinp_xml'
|
|
4
4
|
require 'thinp_xml/distribution'
|
5
5
|
require 'ejt_command_line'
|
6
6
|
|
7
|
+
include ThinpXML
|
8
|
+
|
7
9
|
#----------------------------------------------------------------
|
8
10
|
|
9
11
|
XMLCommandLine = CommandLine::Parser.new do
|
@@ -15,15 +17,8 @@ XMLCommandLine = CommandLine::Parser.new do
|
|
15
17
|
Integer(str)
|
16
18
|
end
|
17
19
|
|
18
|
-
UNIFORM_REGEX = /uniform\[(\d+)..(\d+)\]/
|
19
|
-
|
20
20
|
value_type :int_distribution do |str|
|
21
|
-
|
22
|
-
if m
|
23
|
-
ThinpXML::UniformDistribution.new(m[1].to_i, m[2].to_i + 1)
|
24
|
-
else
|
25
|
-
Integer(str)
|
26
|
-
end
|
21
|
+
parse_distribution(str)
|
27
22
|
end
|
28
23
|
|
29
24
|
simple_switch :help, '--help', '-h'
|
@@ -41,6 +36,8 @@ XMLCommandLine = CommandLine::Parser.new do
|
|
41
36
|
end
|
42
37
|
end
|
43
38
|
|
39
|
+
#--------------------------------
|
40
|
+
|
44
41
|
class Dispatcher
|
45
42
|
include ThinpXML
|
46
43
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
Feature: I can create new metadata
|
2
|
+
|
3
|
+
Scenario: Create a valid superblock with no mappings
|
4
|
+
When I cache_xml create
|
5
|
+
Then the stdout should contain:
|
6
|
+
"""
|
7
|
+
<superblock uuid="" block_size="128" nr_cache_blocks="0">
|
8
|
+
</superblock>
|
9
|
+
"""
|
10
|
+
|
11
|
+
Scenario: Create a valid superblock with specified uuid
|
12
|
+
When I cache_xml create --uuid 'one two three'
|
13
|
+
Then the stdout should contain:
|
14
|
+
"""
|
15
|
+
<superblock uuid="one two three" block_size="128" nr_cache_blocks="0">
|
16
|
+
</superblock>
|
17
|
+
"""
|
18
|
+
|
19
|
+
Scenario: Create a valid superblock with specified block size
|
20
|
+
When I cache_xml create --block-size 512
|
21
|
+
Then the stdout should contain:
|
22
|
+
"""
|
23
|
+
<superblock uuid="" block_size="512" nr_cache_blocks="0">
|
24
|
+
</superblock>
|
25
|
+
"""
|
26
|
+
|
27
|
+
Scenario: Take an integer for the number of cached blocks
|
28
|
+
When I cache_xml create --nr-cache-blocks 345
|
29
|
+
Then the stdout should contain:
|
30
|
+
"""
|
31
|
+
<superblock uuid="" block_size="128" nr_cache_blocks="345">
|
32
|
+
</superblock>
|
33
|
+
"""
|
34
|
+
|
35
|
+
Scenario: Take a uniform distribution for the number of cached blocks
|
36
|
+
When I cache_xml create --nr-cache-blocks uniform[123..124]
|
37
|
+
Then the stdout should contain:
|
38
|
+
"""
|
39
|
+
<superblock uuid="" block_size="128" nr_cache_blocks="123">
|
40
|
+
</superblock>
|
41
|
+
"""
|
42
|
+
|
43
|
+
Scenario: Take an integer for the number of mappings
|
44
|
+
When I cache_xml create --nr-cache-blocks 3 --nr-mappings 3 --layout linear
|
45
|
+
Then the stdout should contain:
|
46
|
+
"""
|
47
|
+
<superblock uuid="" block_size="128" nr_cache_blocks="3">
|
48
|
+
<mapping cache_block="0" origin_block="0" dirty="false"/>
|
49
|
+
<mapping cache_block="1" origin_block="1" dirty="false"/>
|
50
|
+
<mapping cache_block="2" origin_block="2" dirty="false"/>
|
51
|
+
</superblock>
|
52
|
+
"""
|
53
|
+
|
54
|
+
Scenario: Take a percentage for the number of dirty mappings
|
55
|
+
When I cache_xml create --nr-cache-blocks 3 --nr-mappings 3 --layout linear --dirty-percent 100
|
56
|
+
Then the stdout should contain:
|
57
|
+
"""
|
58
|
+
<superblock uuid="" block_size="128" nr_cache_blocks="3">
|
59
|
+
<mapping cache_block="0" origin_block="0" dirty="true"/>
|
60
|
+
<mapping cache_block="1" origin_block="1" dirty="true"/>
|
61
|
+
<mapping cache_block="2" origin_block="2" dirty="true"/>
|
62
|
+
</superblock>
|
63
|
+
"""
|
64
|
+
|
65
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: The tool should be helpful
|
2
|
+
|
3
|
+
Scenario: --help prints usage to stdout
|
4
|
+
When I cache_xml --help
|
5
|
+
Then the stdout should contain:
|
6
|
+
"""
|
7
|
+
Manipulation of cache xml format metadata
|
8
|
+
--help, -h: Show this message
|
9
|
+
"""
|
10
|
+
|
11
|
+
Scenario: Unknown sub commands cause fail
|
12
|
+
When I cache_xml unleashtheearwigs
|
13
|
+
Then it should fail
|
14
|
+
And the stderr should contain:
|
15
|
+
"""
|
16
|
+
unknown command 'unleashtheearwigs'
|
17
|
+
"""
|
File without changes
|
File without changes
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'thinp_xml/cache/metadata'
|
2
|
+
|
3
|
+
#----------------------------------------------------------------
|
4
|
+
|
5
|
+
module CacheXML
|
6
|
+
class Builder
|
7
|
+
attr_accessor :uuid, :block_size, :nr_cache_blocks, :policy_name
|
8
|
+
attr_reader :mapping_policy, :nr_mappings, :dirty_percentage
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@uuid = ''
|
12
|
+
@block_size = 128
|
13
|
+
@nr_cache_blocks = 0
|
14
|
+
@policy_name = 'mq'
|
15
|
+
@mapping_policy = :random
|
16
|
+
@nr_mappings = 0
|
17
|
+
@dirty_percentage = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate
|
21
|
+
superblock = Superblock.new(@uuid, @block_size.to_i, @nr_cache_blocks.to_i, @policy_name)
|
22
|
+
mappings = []
|
23
|
+
|
24
|
+
case @mapping_policy
|
25
|
+
when :linear
|
26
|
+
cb = 0
|
27
|
+
ob = safe_rand(@nr_cache_blocks - @nr_mappings)
|
28
|
+
|
29
|
+
@nr_mappings.times do
|
30
|
+
dirty = safe_rand(100) < @dirty_percentage
|
31
|
+
mappings << Mapping.new(cb, ob, dirty)
|
32
|
+
cb += 1
|
33
|
+
ob += 1
|
34
|
+
end
|
35
|
+
|
36
|
+
when :random
|
37
|
+
origin_blocks = []
|
38
|
+
|
39
|
+
ob = 0
|
40
|
+
@nr_mappings.times do
|
41
|
+
origin_blocks << ob
|
42
|
+
ob += 1
|
43
|
+
end
|
44
|
+
|
45
|
+
0.upto(@nr_mappings - 1) do |n|
|
46
|
+
tmp = origin_blocks[n]
|
47
|
+
|
48
|
+
index = n + rand(@nr_mappings - n)
|
49
|
+
origin_blocks[n] = origin_blocks[index]
|
50
|
+
origin_blocks[index] = tmp
|
51
|
+
|
52
|
+
dirty = safe_rand(100) < @dirty_percentage
|
53
|
+
mappings << Mapping.new(n, origin_blocks[n], dirty)
|
54
|
+
end
|
55
|
+
|
56
|
+
else
|
57
|
+
raise "unknown mapping policy"
|
58
|
+
end
|
59
|
+
|
60
|
+
hints = []
|
61
|
+
|
62
|
+
Metadata.new(superblock, mappings, hints)
|
63
|
+
end
|
64
|
+
|
65
|
+
def mapping_policy=(sym)
|
66
|
+
raise "mapping policy must be :random or :linear" unless valid_policy(sym)
|
67
|
+
@mapping_policy = sym
|
68
|
+
end
|
69
|
+
|
70
|
+
def nr_mappings=(n)
|
71
|
+
n = n.to_i
|
72
|
+
#raise "nr_mappings must not exceed nr_cache_blocks" if n > @nr_cache_blocks
|
73
|
+
@nr_mappings = n
|
74
|
+
end
|
75
|
+
|
76
|
+
def dirty_percentage=(n)
|
77
|
+
raise "invalid percentage (#{n})" if n < 0 || n > 100
|
78
|
+
@dirty_percentage = n
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def valid_policy(sym)
|
83
|
+
[:random, :linear].member?(sym)
|
84
|
+
end
|
85
|
+
|
86
|
+
def safe_rand(n)
|
87
|
+
n == 0 ? 0 : rand(n)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#----------------------------------------------------------------
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'thinp_xml/cache/metadata'
|
2
|
+
require 'thinp_xml/emitter'
|
3
|
+
|
4
|
+
#----------------------------------------------------------------
|
5
|
+
|
6
|
+
module CacheXML
|
7
|
+
module CacheEmitterDetail
|
8
|
+
class CacheEmitter
|
9
|
+
def initialize(out)
|
10
|
+
@e = ThinpXML::Base::Emitter.new(out)
|
11
|
+
end
|
12
|
+
|
13
|
+
def emit_superblock(sb, &block)
|
14
|
+
@e.emit_tag(sb, 'superblock', :uuid, :block_size, :nr_cache_blocks, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def emit_mapping(m)
|
18
|
+
@e.emit_tag(m, 'mapping', :cache_block, :origin_block, :dirty)
|
19
|
+
end
|
20
|
+
|
21
|
+
def emit_hint(h)
|
22
|
+
@e.emit_line("<hint cache_block=\"#{m.cache_block}\" data=\"#{h.encoded_data}\"\>")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#--------------------------------
|
28
|
+
|
29
|
+
def write_xml(metadata, io)
|
30
|
+
e = CacheEmitterDetail::CacheEmitter.new(io)
|
31
|
+
e.emit_superblock(metadata.superblock) do
|
32
|
+
metadata.mappings.each do |m|
|
33
|
+
e.emit_mapping(m)
|
34
|
+
end
|
35
|
+
|
36
|
+
metadata.hints.each do |h|
|
37
|
+
e.emit_hint(h)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#----------------------------------------------------------------
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CacheXML
|
2
|
+
SUPERBLOCK_FIELDS = [[:uuid, :string],
|
3
|
+
[:block_size, :int],
|
4
|
+
[:nr_cache_blocks, :int],
|
5
|
+
[:policy_name, :string]]
|
6
|
+
|
7
|
+
MAPPING_FIELDS = [[:cache_block, :int],
|
8
|
+
[:origin_block, :int],
|
9
|
+
[:dirty, :bool]]
|
10
|
+
|
11
|
+
HINT_FIELDS = [[:cache_block, :int],
|
12
|
+
[:encoded_data, :string]]
|
13
|
+
|
14
|
+
def self.field_names(flds)
|
15
|
+
flds.map {|p| p[0]}
|
16
|
+
end
|
17
|
+
|
18
|
+
Superblock = Struct.new(*field_names(SUPERBLOCK_FIELDS))
|
19
|
+
Mapping = Struct.new(*field_names(MAPPING_FIELDS))
|
20
|
+
Hint = Struct.new(*field_names(HINT_FIELDS))
|
21
|
+
Metadata = Struct.new(:superblock, :mappings, :hints)
|
22
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'thinp_xml/listener'
|
2
|
+
require 'thinp_xml/cache/metadata'
|
3
|
+
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'rexml/streamlistener'
|
6
|
+
|
7
|
+
#----------------------------------------------------------------
|
8
|
+
|
9
|
+
module ThinpXML
|
10
|
+
module CacheParseDetail
|
11
|
+
class Listener
|
12
|
+
include Base::ListenerUtils
|
13
|
+
include REXML::StreamListener
|
14
|
+
|
15
|
+
attr_reader :metadata
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@metadata = Metdadata.new(nil, [], [])
|
19
|
+
end
|
20
|
+
|
21
|
+
def tag_start(tag, args)
|
22
|
+
attr = to_hash(args)
|
23
|
+
|
24
|
+
case tag
|
25
|
+
when 'superblock'
|
26
|
+
@metadata.superblock = Superblock.new(*get_fields(attr, SUPERBLOCK_FIELDS))
|
27
|
+
|
28
|
+
when 'mapping'
|
29
|
+
m = Mapping.new(*get_fields(attr, MAPPING_FIELDS))
|
30
|
+
@metadata.mappings << m
|
31
|
+
|
32
|
+
when 'hint'
|
33
|
+
h = Hint.new(*get_fields(attr, HINT_FIELDS))
|
34
|
+
@metadata.hints << h
|
35
|
+
|
36
|
+
else
|
37
|
+
raise "unhandled tag '#{tag} #{attr.map {|x| x.inspect}.join(' ')}'"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def tag_end(tag)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_xml(io)
|
47
|
+
l = CacheParseDetail::Listener.new
|
48
|
+
REXML::Document.parse_stream(io, l)
|
49
|
+
l.metadata
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#----------------------------------------------------------------
|
@@ -7,10 +7,23 @@ module ThinpXML
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
class
|
10
|
+
class ConstDistribution < Distribution
|
11
|
+
def initialize(v)
|
12
|
+
raise "ConstDistribution must be constructed with an integer" if !v.kind_of?(Integer)
|
13
|
+
@v = v
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate
|
17
|
+
@v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class UniformDistribution < Distribution
|
11
22
|
attr_accessor :start, :stop
|
12
23
|
|
13
24
|
def initialize(start, stop)
|
25
|
+
raise "invalid range [#{start}..#{stop})" unless start < stop
|
26
|
+
|
14
27
|
@start = start
|
15
28
|
@stop = stop
|
16
29
|
end
|
@@ -18,9 +31,18 @@ module ThinpXML
|
|
18
31
|
def generate
|
19
32
|
@start + rand(@stop - @start)
|
20
33
|
end
|
34
|
+
end
|
21
35
|
|
22
|
-
|
23
|
-
|
36
|
+
#--------------------------------
|
37
|
+
|
38
|
+
UNIFORM_REGEX = /uniform\[(\d+)..(\d+)\]/
|
39
|
+
|
40
|
+
def parse_distribution(str)
|
41
|
+
m = UNIFORM_REGEX.match(str)
|
42
|
+
if m
|
43
|
+
ThinpXML::UniformDistribution.new(m[1].to_i, m[2].to_i)
|
44
|
+
else
|
45
|
+
ConstDistribution.new(Integer(str))
|
24
46
|
end
|
25
47
|
end
|
26
48
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#----------------------------------------------------------------
|
2
|
+
|
3
|
+
module ThinpXML
|
4
|
+
module Base
|
5
|
+
class Emitter
|
6
|
+
def initialize(out)
|
7
|
+
@out = out
|
8
|
+
@indent = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def emit_tag(obj, tag, *fields, &block)
|
12
|
+
expanded = fields.map {|fld| "#{fld}=\"#{obj.send(fld)}\""}
|
13
|
+
if block.nil?
|
14
|
+
emit_line "<#{tag} #{expanded.join(' ')}/>"
|
15
|
+
else
|
16
|
+
emit_line "<#{tag} #{expanded.join(' ')}>"
|
17
|
+
push
|
18
|
+
yield unless block.nil?
|
19
|
+
pop
|
20
|
+
emit_line "</#{tag}>"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def emit_line(str)
|
26
|
+
@out.puts((' ' * @indent) + str)
|
27
|
+
end
|
28
|
+
|
29
|
+
def push
|
30
|
+
@indent += 2
|
31
|
+
end
|
32
|
+
|
33
|
+
def pop
|
34
|
+
@indent -= 2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#----------------------------------------------------------------
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#----------------------------------------------------------------
|
2
|
+
|
3
|
+
module ThinpXML
|
4
|
+
module Base
|
5
|
+
module ListenerUtils
|
6
|
+
def to_hash(pairs)
|
7
|
+
r = Hash.new
|
8
|
+
pairs.each do |p|
|
9
|
+
r[p[0].intern] = p[1]
|
10
|
+
end
|
11
|
+
r
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_fields(attr, flds)
|
15
|
+
flds.map do |n,t|
|
16
|
+
case t
|
17
|
+
when :int
|
18
|
+
attr[n].to_i
|
19
|
+
|
20
|
+
when :bool
|
21
|
+
case attr[n]
|
22
|
+
when 'true'
|
23
|
+
true
|
24
|
+
when 'false'
|
25
|
+
false
|
26
|
+
else
|
27
|
+
raise "bad boolean value '#{attr[n]}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
when :string
|
31
|
+
attr[n]
|
32
|
+
|
33
|
+
when :object
|
34
|
+
attr[n]
|
35
|
+
|
36
|
+
else
|
37
|
+
raise "unknown field type"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def text(data)
|
43
|
+
return if data =~ /^\w*$/ # ignore whitespace
|
44
|
+
abbrev = data[0..40] + (data.length > 40 ? "..." : "")
|
45
|
+
puts " text : #{abbrev.inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#----------------------------------------------------------------
|
File without changes
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'thinp_xml/thinp/metadata'
|
2
|
+
require 'thinp_xml/emitter'
|
3
|
+
|
4
|
+
#----------------------------------------------------------------
|
5
|
+
|
6
|
+
module ThinpXML
|
7
|
+
module EmitterDetail
|
8
|
+
class ThinpEmitter
|
9
|
+
def initialize(out)
|
10
|
+
@e = ThinpXML::Base::Emitter.new(out)
|
11
|
+
end
|
12
|
+
|
13
|
+
def emit_superblock(sb, &block)
|
14
|
+
@e.emit_tag(sb, 'superblock', :uuid, :time, :transaction, :data_block_size, :nr_data_blocks, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def emit_device(dev, &block)
|
18
|
+
@e.emit_tag(dev, 'device', :dev_id, :mapped_blocks, :transaction, :creation_time, :snap_time, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def emit_mapping(m)
|
22
|
+
if m.length == 1
|
23
|
+
@e.emit_line("<single_mapping origin_block=\"#{m.origin_begin}\" data_block=\"#{m.data_begin}\" time=\"#{m.time}\"/>")
|
24
|
+
else
|
25
|
+
@e.emit_tag(m, 'range_mapping', :origin_begin, :data_begin, :length, :time)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#--------------------------------
|
32
|
+
|
33
|
+
def write_xml(metadata, io)
|
34
|
+
e = EmitterDetail::ThinpEmitter.new(io)
|
35
|
+
|
36
|
+
e.emit_superblock(metadata.superblock) do
|
37
|
+
metadata.devices.each do |dev|
|
38
|
+
e.emit_device(dev) do
|
39
|
+
dev.mappings.each do |m|
|
40
|
+
e.emit_mapping(m)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#----------------------------------------------------------------
|
File without changes
|
@@ -1,12 +1,17 @@
|
|
1
|
-
require 'thinp_xml/metadata'
|
1
|
+
require 'thinp_xml/thinp/metadata'
|
2
|
+
require 'thinp_xml/listener'
|
3
|
+
|
2
4
|
require 'rexml/document'
|
3
5
|
require 'rexml/streamlistener'
|
4
6
|
|
7
|
+
#----------------------------------------------------------------
|
8
|
+
|
5
9
|
module ThinpXML
|
6
10
|
module ParseDetail
|
7
11
|
include REXML
|
8
12
|
|
9
13
|
class Listener
|
14
|
+
include Base::ListenerUtils
|
10
15
|
include REXML::StreamListener
|
11
16
|
|
12
17
|
attr_reader :metadata
|
@@ -15,31 +20,6 @@ module ThinpXML
|
|
15
20
|
@metadata = Metadata.new(nil, Array.new)
|
16
21
|
end
|
17
22
|
|
18
|
-
def to_hash(pairs)
|
19
|
-
r = Hash.new
|
20
|
-
pairs.each do |p|
|
21
|
-
r[p[0].intern] = p[1]
|
22
|
-
end
|
23
|
-
r
|
24
|
-
end
|
25
|
-
|
26
|
-
def get_fields(attr, flds)
|
27
|
-
flds.map do |n,t|
|
28
|
-
case t
|
29
|
-
when :int
|
30
|
-
attr[n].to_i
|
31
|
-
|
32
|
-
when :string
|
33
|
-
attr[n]
|
34
|
-
|
35
|
-
when :object
|
36
|
-
attr[n]
|
37
|
-
|
38
|
-
else
|
39
|
-
raise "unknown field type"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
23
|
|
44
24
|
def tag_start(tag, args)
|
45
25
|
attr = to_hash(args)
|
@@ -60,18 +40,12 @@ module ThinpXML
|
|
60
40
|
@current_device.mappings << Mapping.new(*get_fields(attr, MAPPING_FIELDS))
|
61
41
|
|
62
42
|
else
|
63
|
-
|
43
|
+
raise "unhandled tag '#{tag} #{attr.map {|x| x.inspect}.join(', ')}'"
|
64
44
|
end
|
65
45
|
end
|
66
46
|
|
67
47
|
def tag_end(tag)
|
68
48
|
end
|
69
|
-
|
70
|
-
def text(data)
|
71
|
-
return if data =~ /^\w*$/ # ignore whitespace
|
72
|
-
abbrev = data[0..40] + (data.length > 40 ? "..." : "")
|
73
|
-
puts " text : #{abbrev.inspect}"
|
74
|
-
end
|
75
49
|
end
|
76
50
|
end
|
77
51
|
|
File without changes
|
data/lib/thinp_xml/version.rb
CHANGED
data/lib/thinp_xml.rb
CHANGED
@@ -10,9 +10,9 @@ unless ThinpXML::tools_are_installed
|
|
10
10
|
raise "please install the thin provisioning tools version #{THINP_TOOLS_VERSION}"
|
11
11
|
end
|
12
12
|
|
13
|
-
require 'thinp_xml/builder'
|
14
|
-
require 'thinp_xml/emit'
|
15
|
-
require 'thinp_xml/metadata'
|
16
|
-
require 'thinp_xml/parse'
|
17
|
-
require 'thinp_xml/utils'
|
13
|
+
require 'thinp_xml/thinp/builder'
|
14
|
+
require 'thinp_xml/thinp/emit'
|
15
|
+
require 'thinp_xml/thinp/metadata'
|
16
|
+
require 'thinp_xml/thinp/parse'
|
17
|
+
require 'thinp_xml/thinp/utils'
|
18
18
|
require 'thinp_xml/version'
|
data/spec/builder_spec.rb
CHANGED
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'thinp_xml/cache/builder'
|
2
|
+
|
3
|
+
#----------------------------------------------------------------
|
4
|
+
|
5
|
+
describe "CacheXML::Builder" do
|
6
|
+
def as_percentage(n, tot)
|
7
|
+
(n * 100) / tot
|
8
|
+
end
|
9
|
+
|
10
|
+
def approx_percentage(n, tot, target)
|
11
|
+
actual = as_percentage(n, tot)
|
12
|
+
(actual - target).abs < 3
|
13
|
+
end
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
@b = CacheXML::Builder.new
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "uuid" do
|
20
|
+
it "should be an empty string by default" do
|
21
|
+
@b.uuid.should == ''
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should reflect any changes" do
|
25
|
+
uuid = 'one two three'
|
26
|
+
@b.uuid = uuid
|
27
|
+
@b.uuid.should == uuid
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should generate the correct uuid" do
|
31
|
+
uuid = 'one two three'
|
32
|
+
@b.uuid = uuid
|
33
|
+
md = @b.generate
|
34
|
+
md.superblock.uuid.should == uuid
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "block_size" do
|
39
|
+
it "should be 128 by default" do
|
40
|
+
@b.block_size.should == 128
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should reflect any changes" do
|
44
|
+
@b.block_size = 512
|
45
|
+
@b.block_size.should == 512
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should generate the correct block size" do
|
49
|
+
bs = 1024
|
50
|
+
@b.block_size = bs
|
51
|
+
md = @b.generate
|
52
|
+
md.superblock.block_size.should == bs
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "nr cache blocks" do
|
57
|
+
it "should be zero by default" do
|
58
|
+
@b.nr_cache_blocks.should == 0
|
59
|
+
@b.generate.should have(0).mappings
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should reflect any changes" do
|
63
|
+
n = rand(1000)
|
64
|
+
@b.nr_cache_blocks = n
|
65
|
+
@b.nr_cache_blocks.should == n
|
66
|
+
@b.generate.superblock.nr_cache_blocks.should == n
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "policy name" do
|
71
|
+
it "should be 'mq' by default" do
|
72
|
+
@b.policy_name.should == 'mq'
|
73
|
+
@b.generate.superblock.policy_name.should == 'mq'
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should reflect changes" do
|
77
|
+
n = 'most_recently_not_used_least'
|
78
|
+
@b.policy_name = n
|
79
|
+
@b.policy_name.should == n
|
80
|
+
@b.generate.superblock.policy_name.should == n
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "mappings" do
|
85
|
+
describe "mapping policy" do
|
86
|
+
it "should default to :random" do
|
87
|
+
@b.mapping_policy.should == :random
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should only accept :random, or :linear" do
|
91
|
+
[:foo, :bar, :jumpy].each do |p|
|
92
|
+
expect {@b.mapping_policy = p}.to raise_error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "nr mappings" do
|
98
|
+
it "should default to zero" do
|
99
|
+
@b.nr_mappings.should == 0
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should never be bigger than the nr_cache_blocks" do
|
103
|
+
100.times do
|
104
|
+
nr_cache = rand(1000)
|
105
|
+
@b.nr_cache_blocks = nr_cache
|
106
|
+
expect {@b.nr_mappings = nr_cache + rand(20) + 1}.to raise_error
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should generate the given number of mappings" do
|
111
|
+
100.times do
|
112
|
+
@b.nr_cache_blocks = rand(1000)
|
113
|
+
@b.nr_mappings = rand(@b.nr_cache_blocks)
|
114
|
+
@b.generate.should have(@b.nr_mappings).mappings
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "dirty percentage" do
|
120
|
+
it "should default to zero" do
|
121
|
+
@b.dirty_percentage.should == 0
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should throw if set to a negative number" do
|
125
|
+
expect do
|
126
|
+
@b.dirty_percentage = -20
|
127
|
+
end.to raise_error(RuntimeError, /-20/)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should throw if set to a > 100 number" do
|
131
|
+
expect do
|
132
|
+
@b.dirty_percentage = 101
|
133
|
+
end.to raise_error(RuntimeError, /101/)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should accept a valid value" do
|
137
|
+
[0, 1, 34, 78, 99, 100].each do |valid_value|
|
138
|
+
@b.dirty_percentage = valid_value
|
139
|
+
@b.dirty_percentage.should == valid_value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should generate the required percentage" do
|
144
|
+
n_mappings = 10000
|
145
|
+
@b.nr_cache_blocks = n_mappings
|
146
|
+
@b.nr_mappings = n_mappings
|
147
|
+
|
148
|
+
[0, 1, 34, 78, 99, 100].each do |p|
|
149
|
+
@b.dirty_percentage = p
|
150
|
+
metadata = @b.generate
|
151
|
+
nr_dirty = 0
|
152
|
+
metadata.mappings.each do |m|
|
153
|
+
nr_dirty += 1 if m.dirty
|
154
|
+
end
|
155
|
+
|
156
|
+
approx_percentage(nr_dirty, n_mappings, p).should be_true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "linear layout" do
|
162
|
+
before :each do
|
163
|
+
@b.mapping_policy = :linear
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should allocate cache blocks in order" do
|
167
|
+
@b.nr_cache_blocks = 100
|
168
|
+
@b.nr_mappings = rand(@b.nr_cache_blocks)
|
169
|
+
mappings = @b.generate.mappings
|
170
|
+
|
171
|
+
cb = 0
|
172
|
+
mappings.each do |m|
|
173
|
+
m.cache_block.should == cb
|
174
|
+
cb += 1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should allocate origin blocks in order" do
|
179
|
+
@b.nr_cache_blocks = 100
|
180
|
+
@b.nr_mappings = 100
|
181
|
+
mappings = @b.generate.mappings
|
182
|
+
|
183
|
+
b = nil
|
184
|
+
mappings.each do |m|
|
185
|
+
if b.nil?
|
186
|
+
b = m.origin_block
|
187
|
+
else
|
188
|
+
m.origin_block.should == b
|
189
|
+
end
|
190
|
+
|
191
|
+
b += 1
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "random mapping" do
|
197
|
+
before :each do
|
198
|
+
@b.mapping_policy = :random
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should allocate cache blocks in order" do
|
202
|
+
@b.nr_cache_blocks = 100
|
203
|
+
@b.nr_mappings = rand(@b.nr_cache_blocks)
|
204
|
+
mappings = @b.generate.mappings
|
205
|
+
|
206
|
+
cb = 0
|
207
|
+
mappings.each do |m|
|
208
|
+
m.cache_block.should == cb
|
209
|
+
cb += 1
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should allocate origin blocks out of order" do
|
214
|
+
@b.nr_cache_blocks = 100
|
215
|
+
@b.nr_mappings = 100
|
216
|
+
mappings = @b.generate.mappings
|
217
|
+
|
218
|
+
in_order = true
|
219
|
+
b = nil
|
220
|
+
mappings.each do |m|
|
221
|
+
if b.nil?
|
222
|
+
b = m.origin_block
|
223
|
+
else
|
224
|
+
if m.origin_block != b
|
225
|
+
in_order = false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
b += 1
|
230
|
+
end
|
231
|
+
|
232
|
+
in_order.should be_false
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
#----------------------------------------------------------------
|
240
|
+
|
data/spec/distribution_spec.rb
CHANGED
@@ -20,12 +20,52 @@ end
|
|
20
20
|
|
21
21
|
#----------------------------------------------------------------
|
22
22
|
|
23
|
-
describe "
|
23
|
+
describe "integer distributions" do
|
24
|
+
describe ConstDistribution do
|
25
|
+
it "should be constructed with a single value" do
|
26
|
+
expect do
|
27
|
+
dist = ConstDistribution.new
|
28
|
+
end.to raise_error
|
29
|
+
|
30
|
+
expect do
|
31
|
+
dist = ConstDistribution.new(1, 2)
|
32
|
+
end.to raise_error
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should always return it's given value" do
|
36
|
+
dist = ConstDistribution.new(5)
|
37
|
+
10.times do
|
38
|
+
dist.generate.should == 5
|
39
|
+
end
|
40
|
+
|
41
|
+
dist = ConstDistribution.new(11)
|
42
|
+
10.times do
|
43
|
+
dist.generate.should == 11
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be passed an integer" do
|
48
|
+
expect do
|
49
|
+
dist = ConstDistribution.new('fish')
|
50
|
+
end.to raise_error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#--------------------------------
|
55
|
+
|
24
56
|
describe UniformDistribution do
|
25
57
|
it "should be constructed with a range of values" do
|
26
58
|
dist = UniformDistribution.new(1, 10)
|
27
59
|
end
|
28
60
|
|
61
|
+
it "should only accept start and stop if they're different" do
|
62
|
+
expect {UniformDistribution.new(45, 45)}.to raise_error
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should only accept start if it's lower than stop" do
|
66
|
+
expect {UniformDistribution.new(45, 35)}.to raise_error
|
67
|
+
end
|
68
|
+
|
29
69
|
it "should generate a number from this range every time generate is called" do
|
30
70
|
dist = UniformDistribution.new(1, 10)
|
31
71
|
|
@@ -39,6 +79,7 @@ describe "random distributions" do
|
|
39
79
|
buckets[10].should == 0
|
40
80
|
|
41
81
|
1.upto(9) do |n|
|
82
|
+
buckets[n].should_not == 0
|
42
83
|
buckets[n].should be_approx(1000, 200)
|
43
84
|
end
|
44
85
|
end
|
@@ -58,6 +99,51 @@ describe "random distributions" do
|
|
58
99
|
$called456.should be_true
|
59
100
|
end
|
60
101
|
end
|
102
|
+
|
103
|
+
#--------------------------------
|
104
|
+
|
105
|
+
describe "parsing" do
|
106
|
+
describe "constant expression" do
|
107
|
+
it "should parse a const expression" do
|
108
|
+
10.times do
|
109
|
+
n = rand(50)
|
110
|
+
parse_distribution(n.to_s).to_i.should == n
|
111
|
+
parse_distribution(n.to_s).to_i.should == n
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "uniform expression" do
|
117
|
+
def check_range(b, e, n)
|
118
|
+
n.should >= b
|
119
|
+
n.should < e
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should accept well formed expressions" do
|
123
|
+
10.times do
|
124
|
+
b, e = [rand(100), rand(100)].sort
|
125
|
+
e += 1
|
126
|
+
d = parse_distribution("uniform[#{b}..#{e}]")
|
127
|
+
|
128
|
+
100.times do
|
129
|
+
check_range(b, e, d.to_i)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should reject badly formed expressions" do
|
135
|
+
bad = ['fred[1..20]',
|
136
|
+
'uniform[1..]',
|
137
|
+
'uniform[..20]',
|
138
|
+
'uniform 1..20',
|
139
|
+
'uniform[1..20',
|
140
|
+
'uniform1..20]']
|
141
|
+
bad.each do |b|
|
142
|
+
expect {parse_distribution(b)}.to raise_error
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
61
147
|
end
|
62
148
|
|
63
149
|
#----------------------------------------------------------------
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thinp_xml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Thornber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ejt_command_line
|
@@ -114,32 +114,45 @@ email:
|
|
114
114
|
- ejt@redhat.com
|
115
115
|
executables:
|
116
116
|
- analyse_metadata
|
117
|
+
- cache_xml
|
117
118
|
- thinp_xml
|
118
119
|
extensions: []
|
119
120
|
extra_rdoc_files: []
|
120
121
|
files:
|
121
122
|
- .gitignore
|
123
|
+
- .rspec
|
122
124
|
- Gemfile
|
123
125
|
- LICENSE.txt
|
124
126
|
- README.md
|
125
127
|
- Rakefile
|
126
128
|
- bin/analyse_metadata
|
129
|
+
- bin/cache_xml
|
127
130
|
- bin/thinp_xml
|
128
|
-
- features/
|
131
|
+
- features/cache_create.feature
|
132
|
+
- features/cache_usage.feature
|
129
133
|
- features/step_definitions/thinp_xml.rb
|
130
134
|
- features/support/env.rb
|
131
|
-
- features/
|
135
|
+
- features/thinp_create.feature
|
136
|
+
- features/thinp_usage.feature
|
132
137
|
- lib/thinp_xml.rb
|
133
|
-
- lib/thinp_xml/
|
134
|
-
- lib/thinp_xml/
|
138
|
+
- lib/thinp_xml/cache/builder.rb
|
139
|
+
- lib/thinp_xml/cache/emit.rb
|
140
|
+
- lib/thinp_xml/cache/metadata.rb
|
141
|
+
- lib/thinp_xml/cache/parse.rb
|
142
|
+
- lib/thinp_xml/cache_xml.rb
|
135
143
|
- lib/thinp_xml/distribution.rb
|
136
|
-
- lib/thinp_xml/
|
137
|
-
- lib/thinp_xml/
|
138
|
-
- lib/thinp_xml/
|
139
|
-
- lib/thinp_xml/
|
144
|
+
- lib/thinp_xml/emitter.rb
|
145
|
+
- lib/thinp_xml/listener.rb
|
146
|
+
- lib/thinp_xml/thinp/analysis.rb
|
147
|
+
- lib/thinp_xml/thinp/builder.rb
|
148
|
+
- lib/thinp_xml/thinp/emit.rb
|
149
|
+
- lib/thinp_xml/thinp/metadata.rb
|
150
|
+
- lib/thinp_xml/thinp/parse.rb
|
151
|
+
- lib/thinp_xml/thinp/utils.rb
|
152
|
+
- lib/thinp_xml/thinp/xml_format.rb
|
140
153
|
- lib/thinp_xml/version.rb
|
141
|
-
- lib/thinp_xml/xml_format.rb
|
142
154
|
- spec/builder_spec.rb
|
155
|
+
- spec/cache_builder_spec.rb
|
143
156
|
- spec/distribution_spec.rb
|
144
157
|
- thinp_xml.gemspec
|
145
158
|
homepage: ''
|
@@ -167,9 +180,12 @@ signing_key:
|
|
167
180
|
specification_version: 4
|
168
181
|
summary: Thin provisioning xml
|
169
182
|
test_files:
|
170
|
-
- features/
|
183
|
+
- features/cache_create.feature
|
184
|
+
- features/cache_usage.feature
|
171
185
|
- features/step_definitions/thinp_xml.rb
|
172
186
|
- features/support/env.rb
|
173
|
-
- features/
|
187
|
+
- features/thinp_create.feature
|
188
|
+
- features/thinp_usage.feature
|
174
189
|
- spec/builder_spec.rb
|
190
|
+
- spec/cache_builder_spec.rb
|
175
191
|
- spec/distribution_spec.rb
|
data/lib/thinp_xml/emit.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
require 'thinp_xml/metadata'
|
2
|
-
|
3
|
-
#----------------------------------------------------------------
|
4
|
-
|
5
|
-
module ThinpXML
|
6
|
-
class Emitter
|
7
|
-
def initialize(out)
|
8
|
-
@out = out
|
9
|
-
@indent = 0
|
10
|
-
end
|
11
|
-
|
12
|
-
def emit_tag(obj, tag, *fields, &block)
|
13
|
-
expanded = fields.map {|fld| "#{fld}=\"#{obj.send(fld)}\""}
|
14
|
-
if block.nil?
|
15
|
-
emit_line "<#{tag} #{expanded.join(' ')}/>"
|
16
|
-
else
|
17
|
-
emit_line "<#{tag} #{expanded.join(' ')}>"
|
18
|
-
push
|
19
|
-
yield unless block.nil?
|
20
|
-
pop
|
21
|
-
emit_line "</#{tag}>"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def emit_line(str)
|
26
|
-
@out.puts((' ' * @indent) + str)
|
27
|
-
end
|
28
|
-
|
29
|
-
def push
|
30
|
-
@indent += 2
|
31
|
-
end
|
32
|
-
|
33
|
-
def pop
|
34
|
-
@indent -= 2
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def emit_superblock(e, sb, &block)
|
39
|
-
e.emit_tag(sb, 'superblock', :uuid, :time, :transaction, :data_block_size, :nr_data_blocks, &block)
|
40
|
-
end
|
41
|
-
|
42
|
-
def emit_device(e, dev, &block)
|
43
|
-
e.emit_tag(dev, 'device', :dev_id, :mapped_blocks, :transaction, :creation_time, :snap_time, &block)
|
44
|
-
end
|
45
|
-
|
46
|
-
def emit_mapping(e, m)
|
47
|
-
if m.length == 1
|
48
|
-
e.emit_line("<single_mapping origin_block=\"#{m.origin_begin}\" data_block=\"#{m.data_begin}\" time=\"#{m.time}\"/>")
|
49
|
-
else
|
50
|
-
e.emit_tag(m, 'range_mapping', :origin_begin, :data_begin, :length, :time)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def write_xml(metadata, io)
|
55
|
-
e = Emitter.new(io)
|
56
|
-
|
57
|
-
emit_superblock(e, metadata.superblock) do
|
58
|
-
metadata.devices.each do |dev|
|
59
|
-
emit_device(e, dev) do
|
60
|
-
dev.mappings.each do |m|
|
61
|
-
emit_mapping(e, m)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
#----------------------------------------------------------------
|