pgdexter 0.3.10 → 0.4.1

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: c604783bd2ae16f3bb648176f96664b31fb6ac50a0094e3d34df195e0a4bb9ee
4
- data.tar.gz: 299487f0880aa486c2678063f1f6bed4fc2398603b5fd9f2ebeb1c27b31cfb26
3
+ metadata.gz: 109808872c6a579e6ce82956d5b2b1da8c66af7c85fae3d5984367e374484eb2
4
+ data.tar.gz: 6fe0f25f316afd84c287ba2fefe5076846c8a572bf2cbee406843abf632ddb2d
5
5
  SHA512:
6
- metadata.gz: 3cbec0f51a8b884d468c92ebca35a47267b82c30c86b281052ae15cd25aa3499d9ad26b4c27fb1c8232a8ecce28bfbf656a44a099d5e28bea6ccc9523f01abe4
7
- data.tar.gz: 8a72520c058109b0f63c41efe79bc91c174fffdca423940c8201a28e94bd4465d4110d9918ba39c505b0fc674ce6e819108d4837ff416f5befaaff9c2bdff4e9
6
+ metadata.gz: c2e5b5d80869c5c90b234af5edbb6d0c0e6118a3dc7191c2d7169209c7ae1505329fb18ea5e3803b045a527dd20b2909a9b2067732dfa030bbce0a931fc88954
7
+ data.tar.gz: 03d139a0f6ac0e967ad4f98685a6d8e513eab0b2022c7a0f7c6d27eca0da9b6441c30480a19acacf5c5f5f0ec762a7243331c3ee752b071015800a98043cad3b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.4.1 (2022-10-15)
2
+
3
+ - Added support for `json` format
4
+
5
+ ## 0.4.0 (2022-07-27)
6
+
7
+ - Added support for pg_query 2
8
+ - Switched to monotonic time
9
+ - Dropped support for Ruby < 2.5
10
+
1
11
  ## 0.3.10 (2021-03-25)
2
12
 
3
13
  - Require pg_query < 2
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The automatic indexer for Postgres
4
4
 
5
- [Read about how it works](https://ankane.org/introducing-dexter)
5
+ [Read about how it works](https://ankane.org/introducing-dexter) or [watch the talk](https://www.youtube.com/watch?v=Mni_1yTaNbE)
6
6
 
7
7
  [![Build Status](https://github.com/ankane/dexter/workflows/build/badge.svg?branch=master)](https://github.com/ankane/dexter/actions)
8
8
 
@@ -12,8 +12,8 @@ First, install [HypoPG](https://github.com/HypoPG/hypopg) on your database serve
12
12
 
13
13
  ```sh
14
14
  cd /tmp
15
- curl -L https://github.com/HypoPG/hypopg/archive/1.2.0.tar.gz | tar xz
16
- cd hypopg-1.2.0
15
+ curl -L https://github.com/HypoPG/hypopg/archive/1.3.1.tar.gz | tar xz
16
+ cd hypopg-1.3.1
17
17
  make
18
18
  make install # may need sudo
19
19
  ```
@@ -32,7 +32,7 @@ And install the command line tool with:
32
32
  gem install pgdexter
33
33
  ```
34
34
 
35
- The command line tool is also available as a [Linux package](guides/Linux.md).
35
+ The command line tool is also available with [Docker](#docker), [Homebrew](#homebrew), or as a [Linux package](guides/Linux.md).
36
36
 
37
37
  ## How to Use
38
38
 
@@ -190,7 +190,37 @@ dexter --log-sql --log-level debug2
190
190
 
191
191
  ## Hosted Postgres
192
192
 
193
- Some hosted providers like Amazon RDS and Heroku do not support the HypoPG extension, which Dexter needs to run. See [how to use Dexter](guides/Hosted-Postgres.md) in these cases.
193
+ Some hosted providers like Amazon RDS and Heroku do not support the HypoPG extension, which Dexter needs to run. See [how to use Dexter](guides/Hosted-Postgres.md) in these cases. To request the extension:
194
+
195
+ - Amazon RDS - follow the instructions on [this page](https://aws.amazon.com/rds/postgresql/faqs/)
196
+ - Google Cloud SQL - star the [feature request](https://issuetracker.google.com/issues/69250435)
197
+ - DigitalOcean Managed Databases - follow the instructions on [this page](https://docs.digitalocean.com/products/databases/postgresql/details/supported-extensions/#supported-extensions)
198
+
199
+ ## Additional Installation Methods
200
+
201
+ ### Docker
202
+
203
+ Get the [Docker image](https://hub.docker.com/r/ankane/dexter) with:
204
+
205
+ ```sh
206
+ docker pull ankane/dexter
207
+ ```
208
+
209
+ And run it with:
210
+
211
+ ```sh
212
+ docker run -ti ankane/dexter <connection-options>
213
+ ```
214
+
215
+ For databases on the host machine, use `host.docker.internal` as the hostname (on Linux, this requires Docker 20.04 and `--add-host=host.docker.internal:host-gateway`).
216
+
217
+ ### Homebrew
218
+
219
+ With Homebrew, you can use:
220
+
221
+ ```sh
222
+ brew install ankane/brew/dexter
223
+ ```
194
224
 
195
225
  ## Future Work
196
226
 
@@ -213,7 +243,7 @@ gem specific_install https://github.com/ankane/dexter.git
213
243
 
214
244
  ## Thanks
215
245
 
216
- This software wouldn’t be possible without [HypoPG](https://github.com/dalibo/hypopg), which allows you to create hypothetical indexes, and [pg_query](https://github.com/lfittl/pg_query), which allows you to parse and fingerprint queries. A big thanks to Dalibo and Lukas Fittl respectively.
246
+ This software wouldn’t be possible without [HypoPG](https://github.com/HypoPG/hypopg), which allows you to create hypothetical indexes, and [pg_query](https://github.com/lfittl/pg_query), which allows you to parse and fingerprint queries. A big thanks to Dalibo and Lukas Fittl respectively.
217
247
 
218
248
  ## Research
219
249
 
@@ -240,6 +240,7 @@ module Dexter
240
240
  end
241
241
 
242
242
  def find_columns(plan)
243
+ plan = JSON.parse(plan.to_json)
243
244
  find_by_key(plan, "ColumnRef")
244
245
  end
245
246
 
@@ -248,20 +249,24 @@ module Dexter
248
249
  end
249
250
 
250
251
  def find_by_key(plan, key)
251
- indexes = []
252
- case plan
253
- when Hash
254
- plan.each do |k, v|
255
- if k == key
256
- indexes << v
257
- else
258
- indexes.concat(find_by_key(v, key))
252
+ result = []
253
+ queue = [plan]
254
+ while queue.any?
255
+ node = queue.pop
256
+ case node
257
+ when Hash
258
+ node.each do |k, v|
259
+ if k == key
260
+ result << v
261
+ elsif !v.nil?
262
+ queue << v
263
+ end
259
264
  end
265
+ when Array
266
+ queue.concat(node)
260
267
  end
261
- when Array
262
- indexes.concat(plan.flat_map { |v| find_by_key(v, key) })
263
268
  end
264
- indexes
269
+ result
265
270
  end
266
271
 
267
272
  def hypo_indexes_from_plan(index_name_to_columns, plan, index_set)
@@ -483,10 +488,10 @@ module Dexter
483
488
  statement = String.new("CREATE INDEX CONCURRENTLY ON #{quote_ident(index[:table])} (#{index[:columns].map { |c| quote_ident(c) }.join(", ")})")
484
489
  statement << " TABLESPACE #{quote_ident(@tablespace)}" if @tablespace
485
490
  log "Creating index: #{statement}"
486
- started_at = Time.now
491
+ started_at = monotonic_time
487
492
  begin
488
493
  execute(statement)
489
- log "Index created: #{((Time.now - started_at) * 1000).to_i} ms"
494
+ log "Index created: #{((monotonic_time - started_at) * 1000).to_i} ms"
490
495
  rescue PG::LockNotAvailable
491
496
  log "Could not acquire lock: #{index[:table]}"
492
497
  end
@@ -498,6 +503,10 @@ module Dexter
498
503
  new_indexes
499
504
  end
500
505
 
506
+ def monotonic_time
507
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
508
+ end
509
+
501
510
  def conn
502
511
  @conn ||= begin
503
512
  # set connect timeout if none set
@@ -0,0 +1,23 @@
1
+ require "json"
2
+
3
+ module Dexter
4
+ class JsonLogParser < LogParser
5
+ FIRST_LINE_REGEX = /\A.+/
6
+
7
+ def perform
8
+ @logfile.each_line do |line|
9
+ row = JSON.parse(line.chomp)
10
+ if (m = REGEX.match(row["message"]))
11
+ # replace first line with match
12
+ # needed for multiline queries
13
+ active_line = row["message"].sub(FIRST_LINE_REGEX, m[3])
14
+
15
+ add_parameters(active_line, row["detail"]) if row["detail"]
16
+ process_entry(active_line, m[1].to_f)
17
+ end
18
+ end
19
+ rescue JSON::ParserError => e
20
+ raise Dexter::Abort, "ERROR: #{e.message}"
21
+ end
22
+ end
23
+ end
@@ -13,6 +13,8 @@ module Dexter
13
13
  PgStatActivityParser.new(@indexer, @collector)
14
14
  elsif options[:input_format] == "csv"
15
15
  CsvLogParser.new(logfile, @collector)
16
+ elsif options[:input_format] == "json"
17
+ JsonLogParser.new(logfile, @collector)
16
18
  elsif options[:input_format] == "sql"
17
19
  SqlLogParser.new(logfile, @collector)
18
20
  else
@@ -62,7 +64,7 @@ module Dexter
62
64
  end
63
65
 
64
66
  def process_queries_without_lock
65
- now = Time.now
67
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
66
68
  min_checked_at = now - 3600 # don't recheck for an hour
67
69
  queries = []
68
70
  @collector.fetch_queries.each do |query|
@@ -1,3 +1,3 @@
1
1
  module Dexter
2
- VERSION = "0.3.10"
2
+ VERSION = "0.4.1"
3
3
  end
data/lib/dexter.rb CHANGED
@@ -4,6 +4,7 @@ require "pg_query"
4
4
  require "slop"
5
5
 
6
6
  # stdlib
7
+ require "json"
7
8
  require "set"
8
9
  require "time"
9
10
 
@@ -15,6 +16,7 @@ require "dexter/collector"
15
16
  require "dexter/indexer"
16
17
  require "dexter/log_parser"
17
18
  require "dexter/csv_log_parser"
19
+ require "dexter/json_log_parser"
18
20
  require "dexter/pg_stat_activity_parser"
19
21
  require "dexter/sql_log_parser"
20
22
  require "dexter/processor"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgdexter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-26 00:00:00.000000000 Z
11
+ date: 2022-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: pg_query
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "<"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '2'
47
+ version: '2.1'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "<"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '2'
54
+ version: '2.1'
55
55
  description:
56
56
  email: andrew@ankane.org
57
57
  executables:
@@ -68,6 +68,7 @@ files:
68
68
  - lib/dexter/collector.rb
69
69
  - lib/dexter/csv_log_parser.rb
70
70
  - lib/dexter/indexer.rb
71
+ - lib/dexter/json_log_parser.rb
71
72
  - lib/dexter/log_parser.rb
72
73
  - lib/dexter/logging.rb
73
74
  - lib/dexter/pg_stat_activity_parser.rb
@@ -87,14 +88,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
88
  requirements:
88
89
  - - ">="
89
90
  - !ruby/object:Gem::Version
90
- version: '2.2'
91
+ version: '2.5'
91
92
  required_rubygems_version: !ruby/object:Gem::Requirement
92
93
  requirements:
93
94
  - - ">="
94
95
  - !ruby/object:Gem::Version
95
96
  version: '0'
96
97
  requirements: []
97
- rubygems_version: 3.2.3
98
+ rubygems_version: 3.3.7
98
99
  signing_key:
99
100
  specification_version: 4
100
101
  summary: The automatic indexer for Postgres