innodb_ruby 0.9.12 → 0.9.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/innodb_space +360 -4
  2. data/lib/innodb/version.rb +1 -1
  3. metadata +2 -2
@@ -11,6 +11,10 @@ def rgb_to_ansi(rgb)
11
11
  16 + (rgb_n[0] * 36) + (rgb_n[1] * 6) + rgb_n[2]
12
12
  end
13
13
 
14
+ def rgb_to_rgbhex(rgb)
15
+ rgb.map { |c| "%02x" % [(c * 255.0).round] }.join
16
+ end
17
+
14
18
  # Interpolate intermediate float-arrays between two float-arrays. Do not
15
19
  # include the points a and b in the result.
16
20
  def interpolate(a, b, count)
@@ -49,6 +53,10 @@ HEATMAP_PROGRESSION = [
49
53
  # Typical heatmap color progression.
50
54
  ANSI_COLORS_HEATMAP = interpolate_sequence(HEATMAP_PROGRESSION, 6).map { |rgb| rgb_to_ansi(rgb) }
51
55
 
56
+ RGBHEX_COLORS_HEATMAP = interpolate_sequence(HEATMAP_PROGRESSION, 41).map { |rgb| rgb_to_rgbhex(rgb) }
57
+
58
+ RGBHEX_COLORS_RANDOM = 100.times.inject([]) { |a, x| a << rgb_to_rgbhex([rand * 0.7 + 0.25, rand * 0.7 + 0.25, rand * 0.7 + 0.25]) }
59
+
52
60
  # The 24-step grayscale progression.
53
61
  ANSI_COLORS_GRAYSCALE = (0xe8..0xff).to_a
54
62
 
@@ -83,6 +91,35 @@ def filled_block(fraction, identifier=nil, block_chars=BLOCK_CHARS_V)
83
91
  end
84
92
  end
85
93
 
94
+ def svg_join_args(args)
95
+ args.map { |arg| "%s=\"%s\"" % [ arg[0], arg[1], ] }.join(" ")
96
+ end
97
+
98
+ def svg(elem, args, content=nil)
99
+ if content
100
+ "<" + elem.to_s + " " + svg_join_args(args) + ">" +
101
+ content.to_s +
102
+ "</" + elem.to_s + ">"
103
+ else
104
+ "<" + elem.to_s + " " + svg_join_args(args) + " />"
105
+ end
106
+ end
107
+
108
+ def svg_path_rounded_rect(x, y, w, h, r)
109
+ [
110
+ "M%i,%i" % [ x + r, y - r ],
111
+ "L%i,%i" % [ x + w - r, y - r ],
112
+ "S%i,%i %i,%i" % [ x + w + r, y - r, x + w + r, y + r ],
113
+ "L%i,%i" % [ x + w + r, y + h - r ],
114
+ "S%i,%i %i,%i" % [ x + w + r, y + h + r, x + w - r, y + h + r ],
115
+ "L%i,%i" % [ x + r, y + h + r ],
116
+ "S%i,%i %i,%i" % [ x - r, y + h + r, x - r, y + h - r ],
117
+ "L%i,%i" % [ x - r, y + r ],
118
+ "S%i,%i %i,%i" % [ x - r, y - r, x + r, y - r ],
119
+ "Z",
120
+ ].join(" ")
121
+ end
122
+
86
123
  # Print metadata about each list in an array of InnoDB::List objects.
87
124
  def print_lists(lists)
88
125
  puts "%-20s%-12s%-12s%-12s%-12s%-12s" % [
@@ -504,6 +541,7 @@ def space_extents_illustrate(space)
504
541
  },
505
542
  ]
506
543
  end
544
+ total_pages = count_by_identifier.values.reduce(:+)
507
545
 
508
546
  puts "%12s ╰%-#{width}s╯" % [ "", "─" * width ]
509
547
 
@@ -516,25 +554,210 @@ def space_extents_illustrate(space)
516
554
  filled_block(1.0, nil),
517
555
  "System",
518
556
  count_by_identifier[nil],
519
- 100.0 * (count_by_identifier[nil].to_f / space.pages.to_f),
557
+ 100.0 * (count_by_identifier[nil].to_f / total_pages.to_f),
520
558
  ]
521
559
  identifiers.sort.each do |identifier, description|
522
560
  puts " %s %-60s %8i %7.2f%%" % [
523
561
  filled_block(1.0, identifier),
524
562
  description,
525
563
  count_by_identifier[identifier],
526
- 100.0 * (count_by_identifier[identifier].to_f / space.pages.to_f),
564
+ 100.0 * (count_by_identifier[identifier].to_f / total_pages.to_f),
527
565
  ]
528
566
  end
529
567
  puts " %s %-60s %8i %7.2f%%" % [
530
568
  filled_block(0.0, nil),
531
569
  "Free space",
532
570
  count_by_identifier[:free],
533
- 100.0 * (count_by_identifier[:free].to_f / space.pages.to_f),
571
+ 100.0 * (count_by_identifier[:free].to_f / total_pages.to_f),
534
572
  ]
535
573
  puts
536
574
  end
537
575
 
576
+ def svg_extent_legend(x, y, block_size, color=nil, description=nil, pages=nil, ratio=nil)
577
+ [
578
+ svg("rect", {
579
+ "y" => y,
580
+ "x" => x,
581
+ "width" => block_size,
582
+ "height" => block_size,
583
+ "fill" => color ? color : "white",
584
+ "stroke" => description ? "black" : "none",
585
+ }),
586
+ svg("text", {
587
+ "y" => y + block_size - 4,
588
+ "x" => x + (description ? block_size + 5 : 0),
589
+ "font-family" => "monospace",
590
+ "font-size" => block_size,
591
+ "font-weight" => description ? "normal" : "bold",
592
+ "text-anchor" => "start",
593
+ }, description ? description : "Page Type"),
594
+ svg("text", {
595
+ "y" => y + block_size - 4,
596
+ "x" => x + block_size + 5 + (40 * block_size),
597
+ "font-family" => "monospace",
598
+ "font-size" => block_size,
599
+ "font-weight" => description ? "normal" : "bold",
600
+ "text-anchor" => "end",
601
+ }, pages ? pages : "Pages"),
602
+ svg("text", {
603
+ "y" => y + block_size - 4,
604
+ "x" => x + block_size + 5 + (40 * block_size) + (10 * block_size),
605
+ "font-family" => "monospace",
606
+ "font-size" => block_size,
607
+ "font-weight" => description ? "normal" : "bold",
608
+ "text-anchor" => "end",
609
+ }, ratio ? ("%7.2f%%" % [ratio]) : "Ratio"),
610
+ ].join("\n")
611
+ end
612
+
613
+ # Illustrate the space by printing each extent and for each page, printing a
614
+ # filled block colored based on the index the page is part of. Print a legend
615
+ # for the colors used afterwards.
616
+ def space_extents_illustrate_svg(space)
617
+ width = space.pages_per_extent
618
+
619
+ puts "<?xml version=\"1.0\"?>"
620
+ puts "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
621
+
622
+ identifiers = {}
623
+ count_by_identifier = Hash.new(0)
624
+
625
+ block_size = 16
626
+ graphic_x = 48
627
+ graphic_y = 16
628
+
629
+ puts svg("text", {
630
+ "y" => graphic_y - 3,
631
+ "x" => graphic_x - 7,
632
+ "font-family" => "monospace",
633
+ "font-size" => block_size,
634
+ "font-weight" => "bold",
635
+ "text-anchor" => "end",
636
+ }, "Page")
637
+
638
+ block_x = 0
639
+ block_y = 0
640
+ space.each_xdes do |entry|
641
+ block_x = 0
642
+
643
+ puts svg("text", {
644
+ "y" => graphic_y + block_y + block_size,
645
+ "x" => graphic_x - 7,
646
+ "font-family" => "monospace",
647
+ "font-size" => block_size,
648
+ "text-anchor" => "end",
649
+ }, entry.xdes[:start_page])
650
+
651
+ entry.each_page_status do |page_number, page_status|
652
+ if page_number < space.pages
653
+ used_fraction = 1.0
654
+ identifier = nil
655
+ if page_status[:free]
656
+ used_fraction = 0.0
657
+ else
658
+ page = space.page(page_number)
659
+ if page.respond_to?(:used_space)
660
+ used_fraction = page.used_space.to_f / page.size.to_f
661
+ end
662
+ if page.respond_to?(:index_id)
663
+ identifier = page.index_id
664
+ unless identifiers[identifier]
665
+ identifiers[identifier] = (page.index_id == Innodb::IbufIndex::INDEX_ID) ?
666
+ "Insert Buffer Index" :
667
+ "Index #{page.index_id}"
668
+ if space.innodb_system
669
+ table, index = space.innodb_system.table_and_index_name_by_id(page.index_id)
670
+ if table && index
671
+ identifiers[identifier] += " (%s.%s)" % [table, index]
672
+ end
673
+ end
674
+ end
675
+ end
676
+ end
677
+ if used_fraction != 0.0
678
+ count_by_identifier[identifier] += 1
679
+ else
680
+ count_by_identifier[:free] += 1
681
+ end
682
+
683
+ block_height = block_size * used_fraction
684
+ color = "black"
685
+ if identifier
686
+ color = "#" + RGBHEX_COLORS_RANDOM[(identifier * COLOR_SPACING_PRIME) % RGBHEX_COLORS_RANDOM.size]
687
+ end
688
+ puts svg("rect", {
689
+ "x" => graphic_x + block_x,
690
+ "y" => graphic_y + block_y + (block_size - block_height),
691
+ "width" => block_size,
692
+ "height" => block_height,
693
+ "fill" => color,
694
+ })
695
+ end
696
+ block_x += block_size
697
+ end
698
+ block_y += block_size
699
+ end
700
+
701
+ puts svg("path", {
702
+ "stroke" => "black",
703
+ "stroke-width" => 1,
704
+ "fill" => "none",
705
+ "d" => svg_path_rounded_rect(
706
+ graphic_x,
707
+ graphic_y,
708
+ block_x,
709
+ block_y,
710
+ 4
711
+ ),
712
+ })
713
+
714
+ block_x = 0
715
+ block_y += 10
716
+ puts svg_extent_legend(
717
+ graphic_x + block_x,
718
+ graphic_y + block_y,
719
+ block_size,
720
+ )
721
+ block_y += block_size + 2
722
+
723
+ puts svg_extent_legend(
724
+ graphic_x + block_x,
725
+ graphic_y + block_y,
726
+ block_size,
727
+ "black",
728
+ "System",
729
+ count_by_identifier[nil],
730
+ 100.0 * (count_by_identifier[nil].to_f / space.pages.to_f)
731
+ )
732
+ block_y += block_size + 2
733
+
734
+ identifiers.sort.each do |identifier, description|
735
+ puts svg_extent_legend(
736
+ graphic_x + block_x,
737
+ graphic_y + block_y,
738
+ block_size,
739
+ "#" + RGBHEX_COLORS_RANDOM[(identifier * COLOR_SPACING_PRIME) % RGBHEX_COLORS_RANDOM.size],
740
+ description,
741
+ count_by_identifier[identifier],
742
+ 100.0 * (count_by_identifier[identifier].to_f / space.pages.to_f)
743
+ )
744
+ block_y += block_size + 2
745
+ end
746
+
747
+ puts svg_extent_legend(
748
+ graphic_x + block_x,
749
+ graphic_y + block_y,
750
+ block_size,
751
+ "white",
752
+ "Free space",
753
+ count_by_identifier[:free],
754
+ 100.0 * (count_by_identifier[:free].to_f / space.pages.to_f)
755
+ )
756
+
757
+ puts "</svg>"
758
+ end
759
+
760
+
538
761
  def space_lsn_age_illustrate(space)
539
762
  colors = ANSI_COLORS_HEATMAP
540
763
 
@@ -615,6 +838,125 @@ def space_lsn_age_illustrate(space)
615
838
  ]
616
839
  end
617
840
 
841
+ def space_lsn_age_illustrate_svg(space)
842
+ colors = RGBHEX_COLORS_HEATMAP
843
+
844
+ puts "<?xml version=\"1.0\"?>"
845
+ puts "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
846
+
847
+ # Calculate the minimum and maximum LSN in the space. This is pretty
848
+ # inefficient as we end up scanning all pages twice.
849
+ page_lsn = Array.new(space.pages)
850
+
851
+ lsn_min = lsn_max = space.page(0).lsn
852
+ space.each_page do |page_number, page|
853
+ if page.lsn != 0
854
+ page_lsn[page_number] = page.lsn
855
+ lsn_min = page.lsn < lsn_min ? page.lsn : lsn_min
856
+ lsn_max = page.lsn > lsn_max ? page.lsn : lsn_max
857
+ end
858
+ end
859
+ lsn_delta = lsn_max - lsn_min
860
+
861
+ block_size = 16
862
+ graphic_x = 48
863
+ graphic_y = 16
864
+
865
+ block_x = 0
866
+ block_y = 0
867
+
868
+ puts svg("text", {
869
+ "y" => graphic_y - 3,
870
+ "x" => graphic_x - 7,
871
+ "font-family" => "monospace",
872
+ "font-size" => block_size,
873
+ "font-weight" => "bold",
874
+ "text-anchor" => "end",
875
+ }, "Page")
876
+
877
+ start_page = 0
878
+ page_lsn.each_slice(64) do |slice|
879
+ block_x = 0
880
+ slice.each do |lsn|
881
+ rgbhex = ""
882
+ if lsn
883
+ age_ratio = (lsn - lsn_min).to_f / lsn_delta.to_f
884
+ color = colors[(age_ratio * colors.size.to_f).floor]
885
+ end
886
+ puts svg("rect", {
887
+ "y" => graphic_y + block_y,
888
+ "x" => graphic_x + block_x,
889
+ "width" => block_size,
890
+ "height" => block_size,
891
+ "fill" => color ? "#" + color : "black",
892
+ })
893
+ block_x += block_size
894
+ end
895
+ puts svg("text", {
896
+ "y" => graphic_y + block_y + block_size,
897
+ "x" => graphic_x - 7,
898
+ "font-family" => "monospace",
899
+ "font-size" => block_size,
900
+ "text-anchor" => "end",
901
+ }, start_page)
902
+ block_y += block_size
903
+ start_page += 64
904
+ end
905
+
906
+ puts svg("path", {
907
+ "stroke" => "black",
908
+ "stroke-width" => 1,
909
+ "fill" => "none",
910
+ "d" => svg_path_rounded_rect(
911
+ graphic_x,
912
+ graphic_y,
913
+ block_x,
914
+ block_y,
915
+ 4
916
+ ),
917
+ })
918
+
919
+ block_x = 0
920
+ block_y += 16
921
+ puts svg("text", {
922
+ "y" => graphic_y + block_y + block_size - 4,
923
+ "x" => graphic_x + block_x,
924
+ "font-family" => "monospace",
925
+ "font-size" => block_size,
926
+ "text-anchor" => "start",
927
+ }, lsn_min)
928
+ color_width = ((64.0 * block_size.to_f) / colors.size.to_f).round
929
+ colors.each do |color|
930
+ puts svg("rect", {
931
+ "y" => graphic_y + block_y + block_size,
932
+ "x" => graphic_x + block_x,
933
+ "width" => color_width,
934
+ "height" => block_size,
935
+ "fill" => "#" + color,
936
+ })
937
+ block_x += color_width
938
+ end
939
+ puts svg("text", {
940
+ "y" => graphic_y + block_y + block_size - 4,
941
+ "x" => graphic_x + block_x,
942
+ "font-family" => "monospace",
943
+ "font-size" => block_size,
944
+ "text-anchor" => "end",
945
+ }, lsn_max)
946
+
947
+ puts svg("text", {
948
+ "y" => graphic_y + block_y + block_size - 4,
949
+ "x" => graphic_x + (block_x / 2),
950
+ "font-family" => "monospace",
951
+ "font-weight" => "bold",
952
+ "font-size" => block_size,
953
+ "text-anchor" => "middle",
954
+ }, "LSN Age")
955
+
956
+
957
+ puts "</svg>\n"
958
+ end
959
+
618
960
  def print_inode_summary(inode)
619
961
  puts "INODE fseg_id=%d, pages=%d, frag=%d, full=%d, not_full=%d, free=%d" % [
620
962
  inode.fseg_id,
@@ -1193,9 +1535,19 @@ The following modes are supported:
1193
1535
  color and Unicode box drawing characters to show page usage throughout
1194
1536
  the space.
1195
1537
 
1538
+ space-extents-illustrate-svg
1539
+ Iterate through all extents, illustrating the extent usage in SVG format
1540
+ printed to stdout to show page usage throughout the space.
1541
+
1196
1542
  space-lsn-age-illustrate
1197
1543
  Iterate through all pages, producing a heat map colored by the page LSN
1198
- allowing the user to get an overview of page modification recency.
1544
+ using ANSI color and Unicode box drawing characters, allowing the user to
1545
+ get an overview of page modification recency.
1546
+
1547
+ space-lsn-age-illustrate-svg
1548
+ Iterate through all pages, producing a heat map colored by the page LSN
1549
+ producing SVG format output, allowing the user to get an overview of page
1550
+ modification recency.
1199
1551
 
1200
1552
  space-inodes-summary
1201
1553
  Iterate through all inodes, printing a short summary of each FSEG.
@@ -1468,8 +1820,12 @@ when "space-extents"
1468
1820
  space_extents(space)
1469
1821
  when "space-extents-illustrate"
1470
1822
  space_extents_illustrate(space)
1823
+ when "space-extents-illustrate-svg"
1824
+ space_extents_illustrate_svg(space)
1471
1825
  when "space-lsn-age-illustrate"
1472
1826
  space_lsn_age_illustrate(space)
1827
+ when "space-lsn-age-illustrate-svg"
1828
+ space_lsn_age_illustrate_svg(space)
1473
1829
  when "space-inodes-summary"
1474
1830
  space_inodes_summary(space)
1475
1831
  when "space-inodes-detail"
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  module Innodb
4
- VERSION = "0.9.12"
4
+ VERSION = "0.9.13"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: innodb_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.12
4
+ version: 0.9.13
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-10-03 00:00:00.000000000 Z
13
+ date: 2015-06-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bindata