catpm 0.6.1 → 0.6.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77d3e9a9e80a64c61ba1cbc9f400f9b53cb774c2eee0cf1fc807952bf1b81c39
4
- data.tar.gz: 3364e29476e9a6f77494f86c0fb00932c70a84eb90067df86e8455a00608930b
3
+ metadata.gz: eac4dbe3e1304875bb2ead1573dc51e3acd760b8dcc18901c122d8004b58e976
4
+ data.tar.gz: c2a94022740f767cebdf44a98e737e495f182ada282528f145ab36deac28daca
5
5
  SHA512:
6
- metadata.gz: 52c5cb2542feabdb2a493390e1fd0c42bef5e5ea8c8d89bb71115f774b790e88b8c8f253402e47835da8190a4113d3ed7302398f59a2ce2841df2576018a20cb
7
- data.tar.gz: be688f7c4ce207e04d09fb1ac30b390bc7f2ea8b050120bc46929a952a632d17e63ffc110950907ee37e60aa62f8f7400a3d982acfc568dd2392d01fe9841c91
6
+ metadata.gz: 499d38cbc6db1313bfb9f77a23476a450617024efbeb0de15c77c33819bf9844d45bbfe3525d8d1b849897a925113aeb4ca93e826f9da49bdd23d0d710bb8f6a
7
+ data.tar.gz: 7db602ccd776bb8882e634c25845ac8792e50644afc72c7c17759ccc701eb4785664f84fc0ec17b46de97142df3a095247b18bbbed000a2f637cd68b12cdc315
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  gem build catpm.gemspec
2
- gem push catpm-0.5.0.gem
2
+ gem push catpm-0.6.0.gem
3
3
 
4
4
  # Catpm
5
5
 
@@ -9,6 +9,7 @@ module Catpm
9
9
  @config = Catpm.config
10
10
  @oldest_bucket = Catpm::Bucket.minimum(:bucket_start)
11
11
  @active_error_count = Catpm::ErrorRecord.unresolved.count
12
+ @table_sizes = Catpm::Adapter.current.table_sizes
12
13
  end
13
14
  end
14
15
  end
@@ -43,6 +43,53 @@
43
43
  </div>
44
44
  </div>
45
45
 
46
+ <%# ─── Storage ─── %>
47
+ <h2>Database Storage</h2>
48
+ <%= section_description("Disk space used by catpm tables in your database.") %>
49
+
50
+ <% total_bytes = @table_sizes.sum { |t| t[:total_bytes].to_i } %>
51
+ <% has_bytes = @table_sizes.any? { |t| t[:total_bytes] } %>
52
+
53
+ <% if has_bytes %>
54
+ <div class="storage-total">
55
+ Total: <strong><%= number_to_human_size(total_bytes) %></strong>
56
+ </div>
57
+ <% end %>
58
+
59
+ <div class="config-table">
60
+ <div class="table-scroll">
61
+ <table>
62
+ <thead>
63
+ <tr>
64
+ <th>Table</th>
65
+ <th style="text-align:right">Rows</th>
66
+ <% if has_bytes %>
67
+ <th style="text-align:right">Size</th>
68
+ <% end %>
69
+ </tr>
70
+ </thead>
71
+ <tbody>
72
+ <% @table_sizes.each do |t| %>
73
+ <tr>
74
+ <td class="mono"><%= t[:name] %></td>
75
+ <td class="mono" style="text-align:right"><%= number_with_delimiter(t[:row_estimate].to_i) %></td>
76
+ <% if has_bytes %>
77
+ <td class="mono" style="text-align:right"><%= number_to_human_size(t[:total_bytes].to_i) %></td>
78
+ <% end %>
79
+ </tr>
80
+ <% end %>
81
+ <% if has_bytes %>
82
+ <tr style="font-weight:600;border-top:2px solid var(--border)">
83
+ <td>Total</td>
84
+ <td class="mono" style="text-align:right"><%= number_with_delimiter(@table_sizes.sum { |t| t[:row_estimate].to_i }) %></td>
85
+ <td class="mono" style="text-align:right"><%= number_to_human_size(total_bytes) %></td>
86
+ </tr>
87
+ <% end %>
88
+ </tbody>
89
+ </table>
90
+ </div>
91
+ </div>
92
+
46
93
  <%# ─── Configuration ─── %>
47
94
  <h2>Configuration</h2>
48
95
  <%= section_description("Current catpm settings. Configure via initializer.") %>
@@ -163,6 +163,9 @@
163
163
  .sample-sidebar { flex: 0 0 320px; }
164
164
  @media (max-width: 900px) { .sample-layout { flex-direction: column; } .sample-sidebar { flex: auto; width: 100%; } }
165
165
 
166
+ /* ─── Storage ─── */
167
+ .storage-total { font-size: 14px; color: var(--text-1); margin-bottom: 12px; }
168
+
166
169
  /* ─── Config Table ─── */
167
170
  .config-table { background: var(--bg-1); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
168
171
  .config-table table { margin: 0; }
@@ -49,6 +49,10 @@ module Catpm
49
49
  raise NotImplementedError
50
50
  end
51
51
 
52
+ def table_sizes
53
+ raise NotImplementedError
54
+ end
55
+
52
56
  def merge_metadata_sum(existing, incoming)
53
57
  existing = parse_json(existing)
54
58
  incoming = parse_json(incoming)
@@ -182,6 +182,23 @@ module Catpm
182
182
  "EXTRACT(EPOCH FROM bucket_start)::integer % #{interval.to_i} = 0"
183
183
  end
184
184
 
185
+ def table_sizes
186
+ ActiveRecord::Base.connection_pool.with_connection do |conn|
187
+ rows = conn.select_all(<<~SQL)
188
+ SELECT c.relname AS name,
189
+ pg_total_relation_size(c.oid) AS total_bytes,
190
+ pg_table_size(c.oid) AS table_bytes,
191
+ pg_indexes_size(c.oid) AS index_bytes,
192
+ c.reltuples::bigint AS row_estimate
193
+ FROM pg_class c
194
+ JOIN pg_namespace n ON n.oid = c.relnamespace
195
+ WHERE c.relname LIKE 'catpm_%' AND c.relkind = 'r' AND n.nspname = 'public'
196
+ ORDER BY pg_total_relation_size(c.oid) DESC
197
+ SQL
198
+ rows.map(&:symbolize_keys)
199
+ end
200
+ end
201
+
185
202
  private
186
203
 
187
204
  def advisory_lock_key(identifier)
@@ -152,6 +152,35 @@ module Catpm
152
152
  "CAST(strftime('%s', bucket_start) AS INTEGER) % #{interval.to_i} = 0"
153
153
  end
154
154
 
155
+ def table_sizes
156
+ conn = ActiveRecord::Base.connection
157
+
158
+ tables = conn.select_values(
159
+ "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'catpm_%' ORDER BY name"
160
+ )
161
+
162
+ has_dbstat = begin
163
+ conn.select_value("SELECT 1 FROM dbstat LIMIT 1")
164
+ true
165
+ rescue StandardError
166
+ false
167
+ end
168
+
169
+ tables.map do |table|
170
+ row_count = conn.select_value("SELECT COUNT(*) FROM \"#{table}\"").to_i
171
+
172
+ total_bytes = if has_dbstat
173
+ objects = [table] + conn.select_values(
174
+ "SELECT name FROM sqlite_master WHERE type='index' AND tbl_name=#{conn.quote(table)}"
175
+ )
176
+ placeholders = objects.map { |n| conn.quote(n) }.join(',')
177
+ conn.select_value("SELECT SUM(pgsize) FROM dbstat WHERE name IN (#{placeholders})").to_i
178
+ end
179
+
180
+ { name: table, total_bytes: total_bytes, row_estimate: row_count }
181
+ end.sort_by { |r| -(r[:total_bytes] || 0) }
182
+ end
183
+
155
184
  private
156
185
 
157
186
  def with_write_lock(&block)
data/lib/catpm/engine.rb CHANGED
@@ -16,9 +16,9 @@ module Catpm
16
16
 
17
17
  if Catpm.config.instrument_middleware_stack
18
18
  app = Rails.application
19
- names = app.middleware.filter_map { |m| m.name }.reject { |n| n.start_with?('Catpm::') }
20
- names.reverse_each do |name|
21
- app.middleware.insert_before(name, Catpm::MiddlewareProbe, name)
19
+ middlewares = app.middleware.reject { |m| m.name&.start_with?('Catpm::') }
20
+ middlewares.reverse_each do |middleware|
21
+ app.middleware.insert_before(middleware, Catpm::MiddlewareProbe, middleware.name)
22
22
  rescue ArgumentError, RuntimeError
23
23
  # Middleware not found in stack — skip
24
24
  end
data/lib/catpm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Catpm
4
- VERSION = '0.6.1'
4
+ VERSION = '0.6.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: catpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''