bricolage 5.15.0 → 5.15.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 +4 -4
- data/jobclass/redis-export.rb +3 -1
- data/lib/bricolage/postgresconnection.rb +32 -1
- data/lib/bricolage/psqldatasource.rb +22 -0
- data/lib/bricolage/redisdatasource.rb +47 -19
- data/lib/bricolage/version.rb +1 -1
- data/test/home/Gemfile.lock +1 -1
- data/test/home/subsys/redis_export.job +5 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 26898f98eb266df22a4940e128b1ae4cf44afd83
|
|
4
|
+
data.tar.gz: fd57e7f63e899b6f9f560a2694a4e1466efcb655
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 46996f94e09c5e9c2efd6814492ebaff39fbdfc1b765a906dbd71dc387b6fecc6bd446a6cd9d916be2479bc0f83588380c3f91afb985ee9ad29f0275c63ed779
|
|
7
|
+
data.tar.gz: fad034727fa9b0781eeb642bda3da779ff8183ea94e7f7eef9d5d5e049a41075c309c8585fcdc37784730fed6713eac26e7979b74f0a2532ce01da83fc96b989
|
data/jobclass/redis-export.rb
CHANGED
|
@@ -14,6 +14,7 @@ JobClass.define('redis-export') {
|
|
|
14
14
|
params.add StringParam.new('key-column', 'REDIS_KEY', 'Redis object key. default: id', optional: true)
|
|
15
15
|
params.add StringParam.new('prefix', 'REDIS_PREFIX', 'Redis object key prefix', optional: true)
|
|
16
16
|
params.add StringParam.new('encode', 'REDIS_ENCODE', 'Redis object encoding. default: hash', optional: true)
|
|
17
|
+
params.add StringParam.new('expire', 'REDIS_TTL', 'Redis object TTL. default: none', optional: true)
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
script {|params, script|
|
|
@@ -24,7 +25,8 @@ JobClass.define('redis-export') {
|
|
|
24
25
|
sql_statement(params),
|
|
25
26
|
params['key-column'] || "id",
|
|
26
27
|
params['prefix'],
|
|
27
|
-
params['encode'] || "hash"
|
|
28
|
+
params['encode'] || "hash",
|
|
29
|
+
expire: params['expire'].to_i
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'bricolage/exception'
|
|
2
|
+
require 'securerandom'
|
|
2
3
|
require 'pg'
|
|
3
4
|
|
|
4
5
|
module Bricolage
|
|
@@ -10,6 +11,7 @@ module Bricolage
|
|
|
10
11
|
@connection = connection
|
|
11
12
|
@ds = ds
|
|
12
13
|
@logger = logger
|
|
14
|
+
@cursor = nil
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def source
|
|
@@ -33,6 +35,36 @@ module Bricolage
|
|
|
33
35
|
exec(query, &block)
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
def execute_query_with_cursor(query, fetch_size, cursor, &block)
|
|
39
|
+
raise "Begin transaction before invoking this method" unless in_transaction?
|
|
40
|
+
if @cursor.nil?
|
|
41
|
+
@cursor = cursor || (0...32).map { alphabets[rand(alphabets.length)] }.join
|
|
42
|
+
declare_cursor = "declare #{@cursor} cursor for #{query}"
|
|
43
|
+
@logger.info "[#{@ds.name}] #{declare_cursor}"
|
|
44
|
+
@connection.exec(declare_cursor)
|
|
45
|
+
elsif !@cursor.nil? && cursor.nil?
|
|
46
|
+
raise "Cursor in use"
|
|
47
|
+
elsif @cursor != cursor
|
|
48
|
+
raise "Invalid cursor"
|
|
49
|
+
end
|
|
50
|
+
fetch = "fetch #{fetch_size} in #{@cursor}"
|
|
51
|
+
@logger.info "[#{@ds.name}] #{fetch}" if cursor.nil?
|
|
52
|
+
yield @connection.exec(fetch)
|
|
53
|
+
return @cursor
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def clear_cursor
|
|
57
|
+
@cursor = nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def alphabets
|
|
61
|
+
@alphabets = @alphabets || [('a'...'z'), ('A'...'Z')].map { |i| i.to_a }.flatten
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def in_transaction?
|
|
65
|
+
@connection.transaction_status == PG::Constants::PQTRANS_INTRANS
|
|
66
|
+
end
|
|
67
|
+
|
|
36
68
|
alias update execute
|
|
37
69
|
|
|
38
70
|
def drop_table(name)
|
|
@@ -88,5 +120,4 @@ module Bricolage
|
|
|
88
120
|
end
|
|
89
121
|
end
|
|
90
122
|
end
|
|
91
|
-
|
|
92
123
|
end
|
|
@@ -110,6 +110,28 @@ module Bricolage
|
|
|
110
110
|
open {|conn| conn.execute_query(query, &block) }
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
+
def cursor_transaction(&block)
|
|
114
|
+
raise "Cursor in use" if cursor_in_transaction?
|
|
115
|
+
conn = PG::Connection.open(host: @host, port: @port, dbname: @database, user: @user, password: password)
|
|
116
|
+
@cur_conn = PostgresConnection.new(conn, self, logger)
|
|
117
|
+
@cur_conn.execute("begin transaction")
|
|
118
|
+
yield
|
|
119
|
+
ensure
|
|
120
|
+
@cur_conn.execute("commit") if cursor_in_transaction?
|
|
121
|
+
@cur_conn.clear_cursor if @cur_conn
|
|
122
|
+
@cur_conn = nil
|
|
123
|
+
conn.close if conn
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def cursor_execute_query(query, fetch_size: 10000, cursor: nil, &block)
|
|
127
|
+
raise "Begin transaction before invoking this method" unless cursor_in_transaction?
|
|
128
|
+
@cur_conn.execute_query_with_cursor(query, fetch_size, cursor, &block)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def cursor_in_transaction?
|
|
132
|
+
@cur_conn && @cur_conn.in_transaction?
|
|
133
|
+
end
|
|
134
|
+
|
|
113
135
|
def drop_table(name)
|
|
114
136
|
open {|conn| conn.drop_table(name) }
|
|
115
137
|
end
|
|
@@ -28,19 +28,19 @@ module Bricolage
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
class RedisTask < DataSourceTask
|
|
31
|
-
def import(src, table, query, key_column, prefix, encode)
|
|
32
|
-
add Import.new(src, table, query, key_column, prefix, encode)
|
|
31
|
+
def import(src, table, query, key_column, prefix, encode, expire: nil)
|
|
32
|
+
add Import.new(src, table, query, key_column, prefix, encode, expire)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
class Import < Action
|
|
36
|
-
def initialize(src, table, query, key_column, prefix, encode)
|
|
36
|
+
def initialize(src, table, query, key_column, prefix, encode, expire)
|
|
37
37
|
@src = src
|
|
38
38
|
@table = table
|
|
39
39
|
@query = query
|
|
40
|
-
@
|
|
41
|
-
puts key_column
|
|
40
|
+
@key_columns = key_column.split(',').map(&:strip)
|
|
42
41
|
@prefix = prefix
|
|
43
42
|
@encode = encode
|
|
43
|
+
@expire = expire
|
|
44
44
|
@read_count = 0
|
|
45
45
|
@write_count = 0
|
|
46
46
|
end
|
|
@@ -58,48 +58,76 @@ module Bricolage
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def import
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
results = []
|
|
62
|
+
@src.cursor_transaction {
|
|
63
|
+
read_count = 0
|
|
64
|
+
loop do
|
|
65
|
+
futures = []
|
|
66
|
+
ds.client.pipelined do
|
|
67
|
+
read_count = read_row do |row|
|
|
68
|
+
futures.push write_row row
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
results.push futures.flatten.map {|f| f.value}.all?
|
|
72
|
+
break if read_count == 0
|
|
73
|
+
end
|
|
74
|
+
}
|
|
75
|
+
@cursor = nil
|
|
76
|
+
results.all?
|
|
64
77
|
end
|
|
65
78
|
|
|
66
79
|
def read_row
|
|
67
|
-
|
|
80
|
+
rs_size = 0
|
|
81
|
+
@cursor = @src.cursor_execute_query(source, cursor: @cursor) do |rs|
|
|
82
|
+
rs_size = rs.values.size
|
|
83
|
+
break if rs_size == 0
|
|
68
84
|
rs.each do |row|
|
|
69
85
|
yield row
|
|
70
86
|
@read_count += 1
|
|
71
87
|
ds.logger.info "Rows read: #{@read_count}" if @read_count % 100000 == 0
|
|
72
88
|
end
|
|
73
89
|
end
|
|
90
|
+
rs_size
|
|
74
91
|
end
|
|
75
92
|
|
|
76
|
-
def write_row(row
|
|
93
|
+
def write_row(row)
|
|
77
94
|
key = key(row)
|
|
95
|
+
data = delete_key_columns(row)
|
|
96
|
+
f = []
|
|
78
97
|
case @encode
|
|
79
98
|
when 'hash'
|
|
80
99
|
# set a value for each key:field pair
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
r.push ds.client.hset(key, field, value)
|
|
100
|
+
data.each do |field,value|
|
|
101
|
+
f.push ds.client.hset(key, field, value)
|
|
84
102
|
end
|
|
85
103
|
when 'json'
|
|
86
|
-
|
|
104
|
+
f.push ds.client.set(key, JSON.generate(data))
|
|
87
105
|
else
|
|
88
106
|
raise %Q("encode: #{type}" is not supported)
|
|
89
107
|
end
|
|
90
|
-
|
|
91
|
-
ds.logger.info "Key sample: #{key}" if @write_count == 0
|
|
108
|
+
f.push ds.client.expire(key, @expire) if @expire
|
|
92
109
|
@write_count += 1
|
|
110
|
+
return f
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def delete_key_columns(row)
|
|
114
|
+
r = row.dup
|
|
115
|
+
@key_columns.each do |key|
|
|
116
|
+
r.delete(key)
|
|
117
|
+
end
|
|
118
|
+
r.empty? ? {1 => 1} : r
|
|
93
119
|
end
|
|
94
120
|
|
|
95
121
|
def key(row)
|
|
96
|
-
|
|
97
|
-
prefix + key_columns.join('_')
|
|
122
|
+
prefix + @key_columns.map {|k| row[k]}.join('_')
|
|
98
123
|
end
|
|
99
124
|
|
|
100
125
|
def run
|
|
101
126
|
begin
|
|
102
|
-
|
|
127
|
+
ds.logger.info "Key Pattern: #{prefix}<#{@key_columns.join('_')}>"
|
|
128
|
+
ds.logger.info "Encode: #{@encode}"
|
|
129
|
+
ds.logger.info "Expire: #{@expire}"
|
|
130
|
+
raise "Unexpected error. Please check data." unless import
|
|
103
131
|
rescue => ex
|
|
104
132
|
ds.logger.error ex.backtrace.join("\n")
|
|
105
133
|
raise JobFailure, ex.message
|
data/lib/bricolage/version.rb
CHANGED
data/test/home/Gemfile.lock
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bricolage
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.15.
|
|
4
|
+
version: 5.15.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Minero Aoki
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-03-
|
|
11
|
+
date: 2016-03-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pg
|