pgdexter 0.3.10 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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