postmodern 0.0.11 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ATTRIBUTION.md +5 -0
- data/Gemfile +1 -0
- data/README.md +75 -1
- data/examples/postmodern_archive.local +17 -0
- data/examples/postmodern_restore.local +14 -0
- data/lib/postmodern.rb +4 -0
- data/lib/postmodern/command.rb +36 -8
- data/lib/postmodern/db/adapter.rb +30 -0
- data/lib/postmodern/dummy.rb +6 -0
- data/lib/postmodern/runner.rb +8 -2
- data/lib/postmodern/vacuum/freeze.rb +33 -0
- data/lib/postmodern/vacuum/vacuum.rb +155 -0
- data/lib/postmodern/version.rb +1 -1
- data/lib/postmodern/wal/archive.rb +3 -4
- data/postmodern.gemspec +2 -0
- data/spec/features/archive_spec.rb +10 -2
- data/spec/features/dummy_spec.rb +26 -7
- data/spec/features/freeze_spec.rb +24 -0
- data/spec/features/restore_spec.rb +44 -0
- data/spec/features/vacuum_spec.rb +24 -0
- data/spec/postmodern/command_spec.rb +24 -0
- data/spec/postmodern/db/adapter_spec.rb +46 -0
- data/spec/postmodern/postmodern_spec.rb +10 -0
- data/spec/postmodern/runner_spec.rb +5 -0
- data/spec/postmodern/vacuum/freeze_spec.rb +59 -0
- data/spec/postmodern/vacuum/vacuum_spec.rb +186 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/logger.rb +9 -0
- metadata +38 -3
- data/lib/postmodern/wal.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bc358882bdb3ac6f246d3967ac261076b4c334d
|
4
|
+
data.tar.gz: 9a3cf7820f70f5271f9ee570be8444bd8305d7e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 619b48a8a1b7b6c250455c143dbe2ac9465066269aea935760e51f7ac6ca9393aacb92a4234a39000fa230de7edb6a5261916e4ccb20c50af8b75ae329ba4e6b
|
7
|
+
data.tar.gz: 3e98b9eeaaa9e57886b00c653e871d2b9816024a17c4c96089abe22cdc6b582a4c8762b7490a5acff54483674296a0170e17dd3f092dfa4cd5429b2e3ef3924e
|
data/ATTRIBUTION.md
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -7,6 +7,11 @@ Tools for managing PostgreSQL databases.
|
|
7
7
|
|
8
8
|
* WAL archiving and restoration
|
9
9
|
|
10
|
+
## Dependencies
|
11
|
+
|
12
|
+
* libpq
|
13
|
+
* [pg gem](http://rubygems.org/gems/pg)
|
14
|
+
|
10
15
|
## Installation
|
11
16
|
|
12
17
|
```bash
|
@@ -18,10 +23,62 @@ the system's ruby, however that is installed.
|
|
18
23
|
|
19
24
|
## Usage
|
20
25
|
|
26
|
+
### Vacuuming and Vacuum Freezing
|
27
|
+
|
28
|
+
Postmodern's vacuum scripts run table by table, with various constraints
|
29
|
+
to limit the overhead of the process.
|
30
|
+
|
31
|
+
```
|
32
|
+
Usage: postmodern (vacuum|freeze) <options>
|
33
|
+
-U, --user USER Defaults to postgres
|
34
|
+
-p, --port PORT Defaults to 5432
|
35
|
+
-H, --host HOST Defaults to 127.0.0.1
|
36
|
+
-W, --password PASS
|
37
|
+
|
38
|
+
-t, --timeout TIMEOUT Halt after timeout minutes -- default 120
|
39
|
+
-d, --database DB Database to vacuum. Required.
|
40
|
+
|
41
|
+
-B, --tablesize BYTES minimum table size to vacuum -- default 1000000
|
42
|
+
-F, --freezeage AGE minimum freeze age -- default 10000000
|
43
|
+
-D, --costdelay DELAY vacuum_cost_delay setting in ms -- default 20
|
44
|
+
-L, --costlimit LIMIT vacuum_cost_limit setting -- default 2000
|
45
|
+
|
46
|
+
-h, --help Show this message
|
47
|
+
--version Show version
|
48
|
+
```
|
49
|
+
|
50
|
+
To run a vacuum:
|
51
|
+
|
52
|
+
```
|
53
|
+
postmodern vacuum -U postgres -p 5432 -d my_database
|
54
|
+
```
|
55
|
+
|
56
|
+
In order to run vacuum freeze:
|
57
|
+
|
58
|
+
```
|
59
|
+
postmodern freeze -U postgres -p 5432 -d my_database
|
60
|
+
```
|
61
|
+
|
62
|
+
These tasks are designed to be run regularly during a window of lower
|
63
|
+
database activity. They vacuum or vacuum freeze each table that requires
|
64
|
+
it (based on command line options). Before each operation, the scripts check
|
65
|
+
to make sure they have not gone longer than `--timeout` seconds.
|
66
|
+
|
21
67
|
### WAL archives
|
22
68
|
|
23
69
|
The wal archiving scripts packaged in this gem are intended to serve as
|
24
|
-
wrappers for YOUR archiving mechanism.
|
70
|
+
wrappers for YOUR archiving mechanism. Changing the settings for WAL
|
71
|
+
archiving in `postgresql.conf` or in `recovery.conf` require full restarts
|
72
|
+
of PostgreSQL—using Postmodern, you can configure PostgreSQL once and swap
|
73
|
+
in local scripts to do the actual work.
|
74
|
+
|
75
|
+
```
|
76
|
+
Usage: postmodern (archive|restore) <options>
|
77
|
+
-f, --filename FILE File name of xlog
|
78
|
+
-p, --path PATH Path of xlog file
|
79
|
+
-h, --help Show this message
|
80
|
+
--version Show version
|
81
|
+
```
|
25
82
|
|
26
83
|
In postgresql.conf
|
27
84
|
|
@@ -51,6 +108,13 @@ the relevant arguments either as $1, $2 or using the variables listed above.
|
|
51
108
|
`archive` will attempt to call a `postmodern_archive.local` script.
|
52
109
|
`restore` will attempt to call a `postmodern_restore.local` script.
|
53
110
|
|
111
|
+
see the [examples](https://github.com/wanelo/postmodern/tree/master/examples)
|
112
|
+
directory for example local scripts.
|
113
|
+
|
114
|
+
## Attribution & Thanks
|
115
|
+
|
116
|
+
Please see the [attribution](https://github.com/wanelo/postmodern/blob/master/ATTRIBUTION.md)
|
117
|
+
file for proper attribution and thanks.
|
54
118
|
|
55
119
|
## Contributing
|
56
120
|
|
@@ -59,3 +123,13 @@ the relevant arguments either as $1, $2 or using the variables listed above.
|
|
59
123
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
60
124
|
4. Push to the branch (`git push origin my-new-feature`)
|
61
125
|
5. Create new Pull Request
|
126
|
+
|
127
|
+
Contributions will not be accepted without tests. What should be a
|
128
|
+
feature and what a unit test is highly open to interpretation, however.
|
129
|
+
In some cases, a unit test may be easier and acceptable. In general,
|
130
|
+
at least one feature should be written for each new subcommand, even
|
131
|
+
if it just runs `--help`.
|
132
|
+
|
133
|
+
If in doubt, open an issue. If you don't receive a response to an issue
|
134
|
+
or a pull request, please mention one of the core committers of this
|
135
|
+
gem in a comment to make sure it doesn't get swallowed in an email abyss.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Local file for running postgres wal log archiving.
|
4
|
+
# Variables are set by postmodern and map to
|
5
|
+
# the following wal archiving conventions:
|
6
|
+
#
|
7
|
+
# WAL_ARCHIVE_PATH = %p
|
8
|
+
# WAL_ARCHIVE_FILE = %f
|
9
|
+
#
|
10
|
+
|
11
|
+
WAL_ARCHIVE_PATH=$1
|
12
|
+
WAL_ARCHIVE_FILE=$2
|
13
|
+
|
14
|
+
mkdir -p /var/pgsql/wal_archive && find /var/pgsql/wal_archive/ -mtime +1 \
|
15
|
+
| xargs rm -f \
|
16
|
+
&& test ! -f /var/pgsql/wal_archive/$WAL_ARCHIVE_FILE \
|
17
|
+
&& cp $WAL_ARCHIVE_PATH /var/pgsql/wal_archive/$WAL_ARCHIVE_FILE
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Local file for running postgres wal log archiving.
|
4
|
+
# Variables are set by postmodern and map to
|
5
|
+
# the following wal archiving conventions:
|
6
|
+
#
|
7
|
+
# WAL_ARCHIVE_PATH = %p
|
8
|
+
# WAL_ARCHIVE_FILE = %f
|
9
|
+
#
|
10
|
+
|
11
|
+
WAL_ARCHIVE_PATH=$1
|
12
|
+
WAL_ARCHIVE_FILE=$2
|
13
|
+
|
14
|
+
cp /var/pgsql/wal_archive/$WAL_ARCHIVE_FILE $WAL_ARCHIVE_PATH
|
data/lib/postmodern.rb
CHANGED
data/lib/postmodern/command.rb
CHANGED
@@ -2,18 +2,38 @@ require 'optparse'
|
|
2
2
|
|
3
3
|
module Postmodern
|
4
4
|
class Command
|
5
|
-
|
6
|
-
|
5
|
+
class << self
|
6
|
+
def inherited(subclass)
|
7
|
+
subclass.instance_variable_set(:@required_options, @required_options)
|
8
|
+
subclass.instance_variable_set(:@default_options, @default_options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def required_options
|
12
|
+
@required_options ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def required_option(*options)
|
16
|
+
required_options.concat(options)
|
17
|
+
required_options.uniq!
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_options
|
21
|
+
@default_options ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_option(key, value)
|
25
|
+
default_options[key] = value
|
26
|
+
end
|
7
27
|
end
|
8
28
|
|
9
29
|
def parser
|
10
|
-
OptionParser
|
30
|
+
raise "Command needs to define an OptionParser"
|
11
31
|
end
|
12
32
|
|
13
33
|
attr_reader :options
|
14
34
|
|
15
35
|
def initialize(args)
|
16
|
-
@options =
|
36
|
+
@options = self.class.default_options.dup
|
17
37
|
|
18
38
|
parse_args(args)
|
19
39
|
validate!
|
@@ -23,15 +43,23 @@ module Postmodern
|
|
23
43
|
end
|
24
44
|
|
25
45
|
def validate!
|
26
|
-
if
|
27
|
-
puts
|
28
|
-
|
46
|
+
if missing_params.any?
|
47
|
+
puts "Missing #{missing_params.join(', ')}"
|
48
|
+
usage!
|
29
49
|
end
|
30
50
|
end
|
31
51
|
|
52
|
+
def missing_params
|
53
|
+
self.class.required_options - self.options.keys
|
54
|
+
end
|
55
|
+
|
32
56
|
def parse_args(args)
|
33
57
|
parser.parse!(args)
|
34
|
-
|
58
|
+
end
|
59
|
+
|
60
|
+
def usage!
|
61
|
+
puts parser.to_s
|
62
|
+
exit 1
|
35
63
|
end
|
36
64
|
end
|
37
65
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
module Postmodern
|
4
|
+
module DB
|
5
|
+
class Adapter
|
6
|
+
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def pg_adapter
|
14
|
+
@pg_adapter ||= PG.connect(db_configuration)
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(sql)
|
18
|
+
pg_adapter.exec(sql)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def db_configuration
|
24
|
+
db_configuration = {}.merge(config)
|
25
|
+
db_configuration.delete(:password) unless config[:password]
|
26
|
+
db_configuration
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/postmodern/dummy.rb
CHANGED
@@ -2,6 +2,11 @@ require 'postmodern/command'
|
|
2
2
|
|
3
3
|
module Postmodern
|
4
4
|
class Dummy < Command
|
5
|
+
def run
|
6
|
+
puts parser
|
7
|
+
exit 1
|
8
|
+
end
|
9
|
+
|
5
10
|
def parser
|
6
11
|
@parser ||= OptionParser.new do |opts|
|
7
12
|
opts.banner = "Usage: postmodern <command> <options>"
|
@@ -10,6 +15,7 @@ module Postmodern
|
|
10
15
|
opts.separator "Available commands:"
|
11
16
|
opts.separator " archive"
|
12
17
|
opts.separator " restore"
|
18
|
+
opts.separator " vacuum"
|
13
19
|
opts.separator ""
|
14
20
|
opts.separator "Options:"
|
15
21
|
|
data/lib/postmodern/runner.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
require 'postmodern
|
1
|
+
require 'postmodern'
|
2
|
+
require 'postmodern/wal/archive'
|
3
|
+
require 'postmodern/wal/restore'
|
4
|
+
require 'postmodern/vacuum/vacuum'
|
5
|
+
require 'postmodern/vacuum/freeze'
|
2
6
|
require 'postmodern/dummy'
|
3
7
|
|
4
8
|
module Postmodern
|
@@ -8,7 +12,9 @@ module Postmodern
|
|
8
12
|
DEFAULT_COMMAND = Dummy
|
9
13
|
COMMAND_MAP = {
|
10
14
|
'archive' => WAL::Archive,
|
11
|
-
'restore' => WAL::Restore
|
15
|
+
'restore' => WAL::Restore,
|
16
|
+
'vacuum' => Vacuum::Vacuum,
|
17
|
+
'freeze' => Vacuum::Freeze
|
12
18
|
}.freeze
|
13
19
|
|
14
20
|
def self.run(args)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'postmodern/vacuum/vacuum'
|
2
|
+
|
3
|
+
module Postmodern
|
4
|
+
module Vacuum
|
5
|
+
class Freeze < Postmodern::Vacuum::Vacuum
|
6
|
+
|
7
|
+
def vacuum_statement table_name
|
8
|
+
"VACUUM FREEZE ANALYZE %s" % table_name
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def table_sql
|
14
|
+
<<-SQL.gsub(/^\s{8}/, '')
|
15
|
+
WITH tabfreeze AS (
|
16
|
+
SELECT pg_class.oid::regclass AS full_table_name,
|
17
|
+
age(relfrozenxid)as freeze_age,
|
18
|
+
pg_relation_size(pg_class.oid)
|
19
|
+
FROM pg_class JOIN pg_namespace ON relnamespace = pg_namespace.oid
|
20
|
+
WHERE nspname not in ('pg_catalog', 'information_schema')
|
21
|
+
AND nspname NOT LIKE 'pg_temp%'
|
22
|
+
AND relkind = 'r'
|
23
|
+
)
|
24
|
+
SELECT full_table_name
|
25
|
+
FROM tabfreeze
|
26
|
+
WHERE freeze_age > #{options[:freezeage]}
|
27
|
+
ORDER BY freeze_age DESC
|
28
|
+
LIMIT 1000;
|
29
|
+
SQL
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'postmodern/command'
|
2
|
+
require 'postmodern/db/adapter'
|
3
|
+
|
4
|
+
module Postmodern
|
5
|
+
module Vacuum
|
6
|
+
class Vacuum < Postmodern::Command
|
7
|
+
default_option :timeout, 120
|
8
|
+
default_option :pause, 10
|
9
|
+
default_option :tablesize, 1000000
|
10
|
+
default_option :freezeage, 10000000
|
11
|
+
default_option :costdelay, 20
|
12
|
+
default_option :costlimit, 2000
|
13
|
+
default_option :user, 'postgres'
|
14
|
+
default_option :port, 5432
|
15
|
+
default_option :host, '127.0.0.1'
|
16
|
+
|
17
|
+
required_option :database
|
18
|
+
|
19
|
+
def parser
|
20
|
+
@parser ||= OptionParser.new do |opts|
|
21
|
+
opts.banner = "Usage: postmodern (vacuum|freeze) <options>"
|
22
|
+
|
23
|
+
opts.on('-U', '--user USER', 'Defaults to postgres') do |opt|
|
24
|
+
self.options[:user] = opt
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on('-p', '--port PORT', 'Defaults to 5432') do |opt|
|
28
|
+
self.options[:port] = opt
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on('-H', '--host HOST', 'Defaults to 127.0.0.1') do |opt|
|
32
|
+
self.options[:host] = opt
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on('-W', '--password PASS') do |opt|
|
36
|
+
self.options[:password] = opt
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.separator ''
|
40
|
+
|
41
|
+
opts.on('-t', '--timeout TIMEOUT', 'Halt after timeout minutes -- default 120') do |opt|
|
42
|
+
self.options[:timeout] = opt
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on('-d', '--database DB', 'Database to vacuum. Required.') do |opt|
|
46
|
+
self.options[:database] = opt
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.separator ''
|
50
|
+
|
51
|
+
opts.on('-B', '--tablesize BYTES', 'minimum table size to vacuum -- default 1000000') do |opt|
|
52
|
+
self.options[:tablesize] = opt
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on('-F', '--freezeage AGE', 'minimum freeze age -- default 10000000') do |opt|
|
56
|
+
self.options[:freezeage] = opt
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on('-D', '--costdelay DELAY', 'vacuum_cost_delay setting in ms -- default 20') do |opt|
|
60
|
+
self.options[:costdelay] = opt
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on('-L', '--costlimit LIMIT', 'vacuum_cost_limit setting -- default 2000') do |opt|
|
64
|
+
self.options[:costlimit] = opt
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.separator ''
|
68
|
+
|
69
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
70
|
+
puts opts
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
|
74
|
+
opts.on_tail("--version", "Show version") do
|
75
|
+
require 'postmodern/version'
|
76
|
+
puts Postmodern::VERSION
|
77
|
+
exit
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
attr_reader :adapter, :start_time
|
83
|
+
|
84
|
+
def initialize(args)
|
85
|
+
@start_time = Time.now
|
86
|
+
super(args)
|
87
|
+
end
|
88
|
+
|
89
|
+
def run
|
90
|
+
configure_vacuum_cost
|
91
|
+
vacuum
|
92
|
+
end
|
93
|
+
|
94
|
+
def configure_vacuum_cost
|
95
|
+
adapter.execute("SET vacuum_cost_delay = '%d ms'" % options[:costdelay])
|
96
|
+
adapter.execute("SET vacuum_cost_limit = '%d'" % options[:costlimit])
|
97
|
+
end
|
98
|
+
|
99
|
+
def vacuum
|
100
|
+
tables_to_vacuum.each do |table|
|
101
|
+
Postmodern.logger.info "Vacuuming #{table}"
|
102
|
+
adapter.execute(vacuum_statement(table))
|
103
|
+
if timedout?
|
104
|
+
Postmodern.logger.warn "Vacuuming timed out"
|
105
|
+
break
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def vacuum_statement table_name
|
111
|
+
"VACUUM ANALYZE %s" % table_name
|
112
|
+
end
|
113
|
+
|
114
|
+
def timedout?
|
115
|
+
Time.now >= start_time + (options[:timeout].to_i * 60)
|
116
|
+
end
|
117
|
+
|
118
|
+
def tables_to_vacuum
|
119
|
+
table_res = adapter.execute(table_sql)
|
120
|
+
table_res.map{|f| f['full_table_name']}
|
121
|
+
end
|
122
|
+
|
123
|
+
def adapter
|
124
|
+
@adapter ||= Postmodern::DB::Adapter.new({
|
125
|
+
dbname: options[:database],
|
126
|
+
port: options[:port],
|
127
|
+
host: options[:host],
|
128
|
+
user: options[:user],
|
129
|
+
password: options[:password]
|
130
|
+
})
|
131
|
+
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
|
135
|
+
def table_sql
|
136
|
+
<<-SQL.gsub(/^\s{8}/, '')
|
137
|
+
WITH deadrow_tables AS (
|
138
|
+
SELECT relid::regclass as full_table_name,
|
139
|
+
((n_dead_tup::numeric) / ( n_live_tup + 1 )) as dead_pct,
|
140
|
+
pg_relation_size(relid) as table_bytes
|
141
|
+
FROM pg_stat_user_tables
|
142
|
+
WHERE n_dead_tup > 100
|
143
|
+
AND ( (now() - last_autovacuum) > INTERVAL '1 hour'
|
144
|
+
OR last_autovacuum IS NULL )
|
145
|
+
)
|
146
|
+
SELECT full_table_name
|
147
|
+
FROM deadrow_tables
|
148
|
+
WHERE dead_pct > 0.05
|
149
|
+
AND table_bytes > #{options[:tablesize]}
|
150
|
+
ORDER BY dead_pct DESC, table_bytes DESC;
|
151
|
+
SQL
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/lib/postmodern/version.rb
CHANGED
@@ -3,15 +3,14 @@ require 'postmodern/command'
|
|
3
3
|
module Postmodern
|
4
4
|
module WAL
|
5
5
|
class Archive < Postmodern::Command
|
6
|
-
|
7
|
-
required_options << :path
|
6
|
+
required_option :filename, :path
|
8
7
|
|
9
8
|
def parser
|
10
9
|
@parser ||= OptionParser.new do |opts|
|
11
10
|
opts.banner = "Usage: postmodern (archive|restore) <options>"
|
12
11
|
|
13
12
|
opts.on('-f', '--filename FILE', 'File name of xlog') do |o|
|
14
|
-
self.options[:
|
13
|
+
self.options[:filename] = o
|
15
14
|
end
|
16
15
|
|
17
16
|
opts.on('-p', '--path PATH', 'Path of xlog file') do |o|
|
@@ -49,7 +48,7 @@ module Postmodern
|
|
49
48
|
end
|
50
49
|
|
51
50
|
def filename
|
52
|
-
@options[:
|
51
|
+
@options[:filename]
|
53
52
|
end
|
54
53
|
|
55
54
|
def local_script_exists?
|
data/postmodern.gemspec
CHANGED
@@ -37,7 +37,11 @@ Usage: postmodern (archive|restore) <options>
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'prints usage' do
|
40
|
-
expect(command).to
|
40
|
+
expect(command).to match(Regexp.escape(usage))
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'includes missing params' do
|
44
|
+
expect(command).to match('Missing path')
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
@@ -49,7 +53,11 @@ Usage: postmodern (archive|restore) <options>
|
|
49
53
|
end
|
50
54
|
|
51
55
|
it 'prints usage' do
|
52
|
-
expect(command).to
|
56
|
+
expect(command).to match(Regexp.escape(usage))
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'includes missing params' do
|
60
|
+
expect(command).to match('Missing filename')
|
53
61
|
end
|
54
62
|
end
|
55
63
|
end
|
data/spec/features/dummy_spec.rb
CHANGED
@@ -1,24 +1,43 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'postmodern/version'
|
3
3
|
|
4
|
-
describe 'dummy
|
5
|
-
|
6
|
-
|
4
|
+
describe 'dummy' do
|
5
|
+
let(:usage) {
|
6
|
+
<<-END
|
7
7
|
Usage: postmodern <command> <options>
|
8
8
|
|
9
9
|
Available commands:
|
10
10
|
archive
|
11
11
|
restore
|
12
|
+
vacuum
|
12
13
|
|
13
14
|
Options:
|
14
15
|
-h, --help Show this message
|
15
16
|
--version Show version
|
16
17
|
END
|
18
|
+
}
|
19
|
+
|
20
|
+
describe 'help' do
|
21
|
+
it 'responds with usage info' do
|
22
|
+
expect(`bin/postmodern --help`).to eq(usage)
|
23
|
+
end
|
17
24
|
end
|
18
|
-
end
|
19
25
|
|
20
|
-
describe '
|
21
|
-
|
22
|
-
|
26
|
+
describe 'version' do
|
27
|
+
it 'responds with the Postmodern version' do
|
28
|
+
expect(`bin/postmodern --version`).to match(Postmodern::VERSION)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'argument catchall' do
|
33
|
+
let(:command) { `bin/postmodern dlaskfjdflf` }
|
34
|
+
|
35
|
+
it 'exits 1' do
|
36
|
+
expect { command }.to have_exit_status(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'prints usage' do
|
40
|
+
expect(command).to eq(usage)
|
41
|
+
end
|
23
42
|
end
|
24
43
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'freeze help' do
|
4
|
+
it 'responds' do
|
5
|
+
expect(`bin/postmodern freeze --help`).to eq <<-END
|
6
|
+
Usage: postmodern (vacuum|freeze) <options>
|
7
|
+
-U, --user USER Defaults to postgres
|
8
|
+
-p, --port PORT Defaults to 5432
|
9
|
+
-H, --host HOST Defaults to 127.0.0.1
|
10
|
+
-W, --password PASS
|
11
|
+
|
12
|
+
-t, --timeout TIMEOUT Halt after timeout minutes -- default 120
|
13
|
+
-d, --database DB Database to vacuum. Required.
|
14
|
+
|
15
|
+
-B, --tablesize BYTES minimum table size to vacuum -- default 1000000
|
16
|
+
-F, --freezeage AGE minimum freeze age -- default 10000000
|
17
|
+
-D, --costdelay DELAY vacuum_cost_delay setting in ms -- default 20
|
18
|
+
-L, --costlimit LIMIT vacuum_cost_limit setting -- default 2000
|
19
|
+
|
20
|
+
-h, --help Show this message
|
21
|
+
--version Show version
|
22
|
+
END
|
23
|
+
end
|
24
|
+
end
|
@@ -15,10 +15,54 @@ end
|
|
15
15
|
describe 'restore' do
|
16
16
|
let(:command) { `bin/postmodern restore --path filepath --filename filename` }
|
17
17
|
|
18
|
+
let(:usage) { <<-END
|
19
|
+
Usage: postmodern (archive|restore) <options>
|
20
|
+
-f, --filename FILE File name of xlog
|
21
|
+
-p, --path PATH Path of xlog file
|
22
|
+
-h, --help Show this message
|
23
|
+
--version Show version
|
24
|
+
END
|
25
|
+
}
|
26
|
+
|
27
|
+
|
18
28
|
before do
|
19
29
|
double_cmd('postmodern_restore.local')
|
20
30
|
end
|
21
31
|
|
32
|
+
describe 'validations' do
|
33
|
+
context 'with no --path' do
|
34
|
+
let(:command) { `bin/postmodern restore --filename filename` }
|
35
|
+
|
36
|
+
it 'fails' do
|
37
|
+
expect { command }.to have_exit_status(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'prints usage' do
|
41
|
+
expect(command).to match(Regexp.escape(usage))
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'includes missing params' do
|
45
|
+
expect(command).to match('Missing path')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with no --filename' do
|
50
|
+
let(:command) { `bin/postmodern restore --path path` }
|
51
|
+
|
52
|
+
it 'fails' do
|
53
|
+
expect { command }.to have_exit_status(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'prints usage' do
|
57
|
+
expect(command).to match(Regexp.escape(usage))
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'includes missing params' do
|
61
|
+
expect(command).to match('Missing filename')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
22
66
|
context 'when local script is present' do
|
23
67
|
before { double_cmd('which', exit: 0) }
|
24
68
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'vacuum help' do
|
4
|
+
it 'responds' do
|
5
|
+
expect(`bin/postmodern vacuum --help`).to eq <<-END
|
6
|
+
Usage: postmodern (vacuum|freeze) <options>
|
7
|
+
-U, --user USER Defaults to postgres
|
8
|
+
-p, --port PORT Defaults to 5432
|
9
|
+
-H, --host HOST Defaults to 127.0.0.1
|
10
|
+
-W, --password PASS
|
11
|
+
|
12
|
+
-t, --timeout TIMEOUT Halt after timeout minutes -- default 120
|
13
|
+
-d, --database DB Database to vacuum. Required.
|
14
|
+
|
15
|
+
-B, --tablesize BYTES minimum table size to vacuum -- default 1000000
|
16
|
+
-F, --freezeage AGE minimum freeze age -- default 10000000
|
17
|
+
-D, --costdelay DELAY vacuum_cost_delay setting in ms -- default 20
|
18
|
+
-L, --costlimit LIMIT vacuum_cost_limit setting -- default 2000
|
19
|
+
|
20
|
+
-h, --help Show this message
|
21
|
+
--version Show version
|
22
|
+
END
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'postmodern/command'
|
3
|
+
|
4
|
+
describe Postmodern::Command do
|
5
|
+
let(:option_parser) { double(parse!: true, to_s: nil) }
|
6
|
+
subject(:command_class) { Class.new(Postmodern::Command) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
local_scope_option_parser = option_parser
|
10
|
+
command_class.send(:define_method, :parser) { local_scope_option_parser }
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
describe '#usage!' do
|
15
|
+
it 'exits 1' do
|
16
|
+
expect { command_class.new([]).usage! }.to raise_error(SystemExit)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'prints parser' do
|
20
|
+
expect { command_class.new([]).usage! }.to raise_error(SystemExit)
|
21
|
+
expect(option_parser).to have_received(:to_s)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'postmodern/db/adapter'
|
3
|
+
|
4
|
+
describe Postmodern::DB::Adapter do
|
5
|
+
subject(:adapter) { Postmodern::DB::Adapter.new(configuration) }
|
6
|
+
|
7
|
+
let(:password) { 'secure...' }
|
8
|
+
let(:configuration) do
|
9
|
+
{
|
10
|
+
stuff: 'things'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#adapter' do
|
15
|
+
context 'with password' do
|
16
|
+
let(:configuration) { {stuff: 'things', password: 'password'} }
|
17
|
+
|
18
|
+
it 'initializes a PG adapter' do
|
19
|
+
expect(PG).to receive(:connect).with({stuff: 'things', password: 'password'})
|
20
|
+
adapter.pg_adapter
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'without password' do
|
25
|
+
let(:configuration) { {stuff: 'things', password: nil} }
|
26
|
+
|
27
|
+
it 'initializes a PG adapter without password params' do
|
28
|
+
expect(PG).to receive(:connect).with({stuff: 'things'})
|
29
|
+
adapter.pg_adapter
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#execute' do
|
35
|
+
let(:pg_adapter) { double }
|
36
|
+
|
37
|
+
before do
|
38
|
+
allow(adapter).to receive(:pg_adapter).and_return(pg_adapter)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'delegates to PG adapter' do
|
42
|
+
expect(pg_adapter).to receive(:exec).with('blah;')
|
43
|
+
adapter.execute('blah;')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -12,6 +12,11 @@ describe Postmodern::Runner do
|
|
12
12
|
expect(Postmodern::Runner.command_for('restore')).to be Postmodern::WAL::Restore
|
13
13
|
end
|
14
14
|
|
15
|
+
|
16
|
+
it 'chooses vacuumer' do
|
17
|
+
expect(Postmodern::Runner.command_for('vacuum')).to be Postmodern::Vacuum::Vacuum
|
18
|
+
end
|
19
|
+
|
15
20
|
it 'defaults to dummy' do
|
16
21
|
expect(Postmodern::Runner.command_for('ljfaldf')).to be Postmodern::Dummy
|
17
22
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'postmodern/vacuum/freeze'
|
3
|
+
|
4
|
+
describe Postmodern::Vacuum::Freeze do
|
5
|
+
let(:adapter) { double }
|
6
|
+
let(:args) { %w(-d db) }
|
7
|
+
subject(:command) { Postmodern::Vacuum::Freeze.new(args) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(Postmodern).to receive(:logger).and_return(FakeLogger.new)
|
11
|
+
allow(adapter).to receive(:execute)
|
12
|
+
allow(command).to receive(:adapter).and_return(adapter)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#tables_to_vacuum' do
|
16
|
+
let(:args) { %w(-d mydb -F 12345) }
|
17
|
+
|
18
|
+
it 'finds list of tables to vacuum' do
|
19
|
+
result = [
|
20
|
+
{'full_table_name' => 'table1'},
|
21
|
+
{'full_table_name' => 'table2'},
|
22
|
+
]
|
23
|
+
allow(command).to receive(:adapter).and_return(adapter)
|
24
|
+
expect(adapter).to receive(:execute).with(%Q{WITH tabfreeze AS (
|
25
|
+
SELECT pg_class.oid::regclass AS full_table_name,
|
26
|
+
age(relfrozenxid)as freeze_age,
|
27
|
+
pg_relation_size(pg_class.oid)
|
28
|
+
FROM pg_class JOIN pg_namespace ON relnamespace = pg_namespace.oid
|
29
|
+
WHERE nspname not in ('pg_catalog', 'information_schema')
|
30
|
+
AND nspname NOT LIKE 'pg_temp%'
|
31
|
+
AND relkind = 'r'
|
32
|
+
)
|
33
|
+
SELECT full_table_name
|
34
|
+
FROM tabfreeze
|
35
|
+
WHERE freeze_age > 12345
|
36
|
+
ORDER BY freeze_age DESC
|
37
|
+
LIMIT 1000;
|
38
|
+
}).and_return(result)
|
39
|
+
|
40
|
+
expect(command.tables_to_vacuum).to eq(%w(table1 table2))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#vacuum' do
|
45
|
+
let(:tables_to_vacuum) { %w(table1 table2 table3) }
|
46
|
+
|
47
|
+
before do
|
48
|
+
allow(Postmodern::DB::Adapter).to receive(:new).and_return(adapter)
|
49
|
+
allow(command).to receive(:tables_to_vacuum).and_return(tables_to_vacuum)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "vacuums each table" do
|
53
|
+
command.vacuum
|
54
|
+
tables_to_vacuum.each do |table|
|
55
|
+
expect(adapter).to have_received(:execute).with("VACUUM FREEZE ANALYZE %s" % table)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'postmodern/vacuum/vacuum'
|
3
|
+
require 'timecop'
|
4
|
+
|
5
|
+
describe Postmodern::Vacuum::Vacuum do
|
6
|
+
let(:args) { %w(-d mydb) }
|
7
|
+
let(:adapter) { double }
|
8
|
+
subject(:command) { Postmodern::Vacuum::Vacuum.new(args) }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(Postmodern).to receive(:logger).and_return(FakeLogger.new)
|
12
|
+
allow(adapter).to receive(:execute)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#options" do
|
16
|
+
{
|
17
|
+
user: 'postgres',
|
18
|
+
port: 5432,
|
19
|
+
host: '127.0.0.1',
|
20
|
+
timeout: 120,
|
21
|
+
pause: 10,
|
22
|
+
tablesize: 1000000,
|
23
|
+
freezeage: 10000000,
|
24
|
+
costdelay: 20,
|
25
|
+
costlimit: 2000
|
26
|
+
}.each do |option, default|
|
27
|
+
it "defaults on #{option}" do
|
28
|
+
expect(command.options[option]).to eq(default)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'validations' do
|
34
|
+
let(:usage) { double(usage!: '') }
|
35
|
+
|
36
|
+
before do
|
37
|
+
allow_any_instance_of(Postmodern::Vacuum::Vacuum).
|
38
|
+
to receive(:usage!) { usage.usage! }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'database' do
|
42
|
+
it 'requires database' do
|
43
|
+
Postmodern::Vacuum::Vacuum.new([])
|
44
|
+
expect(usage).to have_received(:usage!)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#run" do
|
50
|
+
let(:args) { %w(--database mydb) }
|
51
|
+
|
52
|
+
before do
|
53
|
+
allow(command).to receive(:adapter).and_return(adapter)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'executes vacuum operations in order' do
|
57
|
+
expect(command).to receive(:configure_vacuum_cost).once
|
58
|
+
expect(command).to receive(:vacuum).once
|
59
|
+
command.run
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#adapter' do
|
64
|
+
before { allow(adapter).to receive(:execute) }
|
65
|
+
|
66
|
+
it 'instantiates a DB::Adapter' do
|
67
|
+
expect(Postmodern::DB::Adapter).to receive(:new).once.with({
|
68
|
+
dbname: 'mydb',
|
69
|
+
port: 5432,
|
70
|
+
host: '127.0.0.1',
|
71
|
+
user: 'postgres',
|
72
|
+
password: nil
|
73
|
+
}).and_return(adapter)
|
74
|
+
command.adapter
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when password is present' do
|
78
|
+
let(:args) { %w(--password mypass --database mydb) }
|
79
|
+
it 'passes through to adapter' do
|
80
|
+
expect(Postmodern::DB::Adapter).to receive(:new).once.with({
|
81
|
+
dbname: 'mydb',
|
82
|
+
port: 5432,
|
83
|
+
host: '127.0.0.1',
|
84
|
+
user: 'postgres',
|
85
|
+
password: 'mypass'
|
86
|
+
}).and_return(adapter)
|
87
|
+
command.adapter
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#configure_vacuum_cost' do
|
93
|
+
before do
|
94
|
+
allow(command).to receive(:adapter).and_return(adapter)
|
95
|
+
command.configure_vacuum_cost
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'sets vacuum cost delay' do
|
99
|
+
expect(adapter).to have_received(:execute).with("SET vacuum_cost_delay = '#{command.options[:costdelay]} ms'")
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'sets vacuum cost limit' do
|
103
|
+
expect(adapter).to have_received(:execute).with("SET vacuum_cost_limit = '#{command.options[:costlimit]}'")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '#tables_to_vacuum' do
|
108
|
+
let(:args) { %w(-d mydb -B 12345) }
|
109
|
+
|
110
|
+
it 'finds list of tables to vacuum' do
|
111
|
+
result = [
|
112
|
+
{ 'full_table_name' => 'table1'},
|
113
|
+
{ 'full_table_name' => 'table2'},
|
114
|
+
]
|
115
|
+
allow(command).to receive(:adapter).and_return(adapter)
|
116
|
+
expect(adapter).to receive(:execute).with(%Q{WITH deadrow_tables AS (
|
117
|
+
SELECT relid::regclass as full_table_name,
|
118
|
+
((n_dead_tup::numeric) / ( n_live_tup + 1 )) as dead_pct,
|
119
|
+
pg_relation_size(relid) as table_bytes
|
120
|
+
FROM pg_stat_user_tables
|
121
|
+
WHERE n_dead_tup > 100
|
122
|
+
AND ( (now() - last_autovacuum) > INTERVAL '1 hour'
|
123
|
+
OR last_autovacuum IS NULL )
|
124
|
+
)
|
125
|
+
SELECT full_table_name
|
126
|
+
FROM deadrow_tables
|
127
|
+
WHERE dead_pct > 0.05
|
128
|
+
AND table_bytes > 12345
|
129
|
+
ORDER BY dead_pct DESC, table_bytes DESC;
|
130
|
+
}).and_return(result)
|
131
|
+
|
132
|
+
expect(command.tables_to_vacuum).to eq(%w(table1 table2))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "#vacuum" do
|
137
|
+
before do
|
138
|
+
allow(Postmodern::DB::Adapter).to receive(:new).and_return(adapter)
|
139
|
+
allow(command).to receive(:tables_to_vacuum).and_return(tables_to_vacuum)
|
140
|
+
end
|
141
|
+
|
142
|
+
let(:tables_to_vacuum) { %w(table1 table2 table3) }
|
143
|
+
|
144
|
+
it "vacuums each table" do
|
145
|
+
command.vacuum
|
146
|
+
tables_to_vacuum.each do |table|
|
147
|
+
expect(adapter).to have_received(:execute).with("VACUUM ANALYZE %s" % table)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it "exits prematurely with a timeout and analyzes first table" do
|
152
|
+
allow(command).to receive(:timedout?).and_return(true)
|
153
|
+
command.vacuum
|
154
|
+
expect(adapter).to have_received(:execute).with("VACUUM ANALYZE %s" % tables_to_vacuum[0])
|
155
|
+
expect(adapter).not_to have_received(:execute).with("VACUUM ANALYZE %s" % tables_to_vacuum[1])
|
156
|
+
expect(adapter).not_to have_received(:execute).with("VACUUM ANALYZE %s" % tables_to_vacuum[2])
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#timedout?' do
|
161
|
+
let(:time) { Time.now }
|
162
|
+
let(:args) { %w(--d db -t 15) }
|
163
|
+
|
164
|
+
before do
|
165
|
+
Timecop.freeze time do
|
166
|
+
command # ensure command is initialized Now
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'current time is greater than timeout threshold since initialization' do
|
171
|
+
it 'is true' do
|
172
|
+
Timecop.freeze time + (15 * 60) do
|
173
|
+
expect(command.timedout?).to be true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'current time is less than timeout threshold since initialization' do
|
179
|
+
it 'is false' do
|
180
|
+
Timecop.freeze time + (15 * 60 - 1) do
|
181
|
+
expect(command.timedout?).to be false
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'aruba/rspec'
|
2
2
|
require 'pry'
|
3
|
+
require 'timecop'
|
4
|
+
|
5
|
+
require 'support/logger'
|
3
6
|
|
4
7
|
RSpec.configure do |config|
|
5
8
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
@@ -16,5 +19,6 @@ RSpec.configure do |config|
|
|
16
19
|
|
17
20
|
config.after :each do
|
18
21
|
Aruba::RSpec.teardown
|
22
|
+
Timecop.return
|
19
23
|
end
|
20
24
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: postmodern
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Saxby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pg
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -49,28 +63,41 @@ files:
|
|
49
63
|
- ".gitignore"
|
50
64
|
- ".rspec"
|
51
65
|
- ".travis.yml"
|
66
|
+
- ATTRIBUTION.md
|
52
67
|
- Gemfile
|
53
68
|
- Guardfile
|
54
69
|
- LICENSE.txt
|
55
70
|
- README.md
|
56
71
|
- Rakefile
|
57
72
|
- bin/postmodern
|
73
|
+
- examples/postmodern_archive.local
|
74
|
+
- examples/postmodern_restore.local
|
58
75
|
- lib/postmodern.rb
|
59
76
|
- lib/postmodern/command.rb
|
77
|
+
- lib/postmodern/db/adapter.rb
|
60
78
|
- lib/postmodern/dummy.rb
|
61
79
|
- lib/postmodern/runner.rb
|
80
|
+
- lib/postmodern/vacuum/freeze.rb
|
81
|
+
- lib/postmodern/vacuum/vacuum.rb
|
62
82
|
- lib/postmodern/version.rb
|
63
|
-
- lib/postmodern/wal.rb
|
64
83
|
- lib/postmodern/wal/archive.rb
|
65
84
|
- lib/postmodern/wal/restore.rb
|
66
85
|
- postmodern.gemspec
|
67
86
|
- spec/features/archive_spec.rb
|
68
87
|
- spec/features/dummy_spec.rb
|
88
|
+
- spec/features/freeze_spec.rb
|
69
89
|
- spec/features/restore_spec.rb
|
90
|
+
- spec/features/vacuum_spec.rb
|
91
|
+
- spec/postmodern/command_spec.rb
|
92
|
+
- spec/postmodern/db/adapter_spec.rb
|
93
|
+
- spec/postmodern/postmodern_spec.rb
|
70
94
|
- spec/postmodern/runner_spec.rb
|
95
|
+
- spec/postmodern/vacuum/freeze_spec.rb
|
96
|
+
- spec/postmodern/vacuum/vacuum_spec.rb
|
71
97
|
- spec/postmodern/wal/archive_spec.rb
|
72
98
|
- spec/postmodern/wal/restore_spec.rb
|
73
99
|
- spec/spec_helper.rb
|
100
|
+
- spec/support/logger.rb
|
74
101
|
homepage: https://github.com/wanelo/postmodern
|
75
102
|
licenses:
|
76
103
|
- MIT
|
@@ -98,9 +125,17 @@ summary: Tools for managing PostgreSQL
|
|
98
125
|
test_files:
|
99
126
|
- spec/features/archive_spec.rb
|
100
127
|
- spec/features/dummy_spec.rb
|
128
|
+
- spec/features/freeze_spec.rb
|
101
129
|
- spec/features/restore_spec.rb
|
130
|
+
- spec/features/vacuum_spec.rb
|
131
|
+
- spec/postmodern/command_spec.rb
|
132
|
+
- spec/postmodern/db/adapter_spec.rb
|
133
|
+
- spec/postmodern/postmodern_spec.rb
|
102
134
|
- spec/postmodern/runner_spec.rb
|
135
|
+
- spec/postmodern/vacuum/freeze_spec.rb
|
136
|
+
- spec/postmodern/vacuum/vacuum_spec.rb
|
103
137
|
- spec/postmodern/wal/archive_spec.rb
|
104
138
|
- spec/postmodern/wal/restore_spec.rb
|
105
139
|
- spec/spec_helper.rb
|
140
|
+
- spec/support/logger.rb
|
106
141
|
has_rdoc:
|
data/lib/postmodern/wal.rb
DELETED