flydata 0.6.14 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/flydata-core/Gemfile +1 -0
- data/flydata-core/Gemfile.lock +5 -0
- data/flydata-core/lib/flydata-core/errors.rb +4 -2
- data/flydata-core/lib/flydata-core/mysql/binlog_pos.rb +4 -0
- data/flydata-core/lib/flydata-core/postgresql/compatibility_checker.rb +119 -0
- data/flydata-core/lib/flydata-core/postgresql/config.rb +58 -0
- data/flydata-core/lib/flydata-core/postgresql/pg_client.rb +170 -0
- data/flydata-core/lib/flydata-core/postgresql/snapshot.rb +49 -0
- data/flydata-core/lib/flydata-core/postgresql/source_pos.rb +71 -10
- data/flydata-core/lib/flydata-core/table_def/mysql_table_def.rb +1 -1
- data/flydata-core/lib/flydata-core/table_def/postgresql_table_def.rb +76 -17
- data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +59 -10
- data/flydata-core/spec/mysql/binlog_pos_spec.rb +10 -2
- data/flydata-core/spec/postgresql/compatibility_checker_spec.rb +148 -0
- data/flydata-core/spec/postgresql/config_spec.rb +85 -0
- data/flydata-core/spec/postgresql/pg_client_spec.rb +195 -0
- data/flydata-core/spec/postgresql/snapshot_spec.rb +55 -0
- data/flydata-core/spec/postgresql/source_pos_spec.rb +70 -8
- data/flydata-core/spec/table_def/postgresql_table_def_spec.rb +80 -19
- data/flydata-core/spec/table_def/redshift_table_def_spec.rb +211 -14
- data/flydata.gemspec +0 -0
- data/lib/flydata.rb +1 -0
- data/lib/flydata/command/sender.rb +10 -7
- data/lib/flydata/command/sync.rb +4 -1
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/base.rb +1 -0
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/fluent_log_ext.rb +73 -0
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync.rb +35 -10
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync_diff_based.rb +29 -0
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync_query_based.rb +26 -0
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/preference.rb +29 -13
- data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +10 -18
- data/lib/flydata/fluent-plugins/in_postgresql_query_based_flydata.rb +64 -0
- data/lib/flydata/helpers.rb +1 -3
- data/lib/flydata/plugin_support/context.rb +14 -2
- data/lib/flydata/plugin_support/source_position_file.rb +35 -0
- data/lib/flydata/plugin_support/sync_record_emittable.rb +2 -1
- data/lib/flydata/query_based_sync/client.rb +101 -0
- data/lib/flydata/query_based_sync/record_size_estimator.rb +39 -0
- data/lib/flydata/query_based_sync/resource_requester.rb +70 -0
- data/lib/flydata/query_based_sync/response.rb +122 -0
- data/lib/flydata/query_based_sync/response_handler.rb +30 -0
- data/lib/flydata/source/sync_generate_table_ddl.rb +1 -1
- data/lib/flydata/source_mysql/plugin_support/binlog_record_dispatcher.rb +2 -2
- data/lib/flydata/source_mysql/plugin_support/binlog_record_handler.rb +3 -9
- data/lib/flydata/source_mysql/plugin_support/context.rb +26 -2
- data/lib/flydata/source_mysql/plugin_support/source_position_file.rb +14 -0
- data/lib/flydata/source_mysql/table_ddl.rb +3 -3
- data/lib/flydata/source_mysql/{plugin_support/table_meta.rb → table_meta.rb} +3 -10
- data/lib/flydata/source_postgresql/generate_source_dump.rb +44 -63
- data/lib/flydata/source_postgresql/parse_dump_and_send.rb +2 -0
- data/lib/flydata/source_postgresql/plugin_support/context.rb +13 -0
- data/lib/flydata/source_postgresql/plugin_support/source_position_file.rb +14 -0
- data/lib/flydata/source_postgresql/query_based_sync/client.rb +16 -0
- data/lib/flydata/source_postgresql/query_based_sync/diff_query_generator.rb +135 -0
- data/lib/flydata/source_postgresql/query_based_sync/resource_requester.rb +86 -0
- data/lib/flydata/source_postgresql/query_based_sync/response.rb +12 -0
- data/lib/flydata/source_postgresql/query_based_sync/response_handler.rb +12 -0
- data/lib/flydata/source_postgresql/sync_generate_table_ddl.rb +25 -79
- data/lib/flydata/source_postgresql/table_meta.rb +168 -0
- data/lib/flydata/sync_file_manager.rb +5 -5
- data/lib/flydata/table_meta.rb +19 -0
- data/spec/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync_context.rb +85 -0
- data/spec/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync_diff_based_shared_examples.rb +36 -0
- data/spec/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync_query_based_shared_examples.rb +37 -0
- data/spec/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync_shared_examples.rb +67 -0
- data/spec/flydata/fluent-plugins/in_mysql_binlog_flydata_spec.rb +119 -96
- data/spec/flydata/fluent-plugins/in_postgresql_query_based_flydata_spec.rb +82 -0
- data/spec/flydata/fluent-plugins/sync_source_plugin_context.rb +29 -0
- data/spec/flydata/plugin_support/context_spec.rb +37 -3
- data/spec/flydata/query_based_sync/client_spec.rb +79 -0
- data/spec/flydata/query_based_sync/query_based_sync_context.rb +116 -0
- data/spec/flydata/query_based_sync/record_size_estimator_spec.rb +54 -0
- data/spec/flydata/query_based_sync/resource_requester_spec.rb +58 -0
- data/spec/flydata/query_based_sync/response_handler_spec.rb +36 -0
- data/spec/flydata/query_based_sync/response_spec.rb +157 -0
- data/spec/flydata/source_mysql/plugin_support/context_spec.rb +7 -1
- data/spec/flydata/source_mysql/plugin_support/dml_record_handler_spec.rb +2 -15
- data/spec/flydata/source_mysql/plugin_support/drop_database_query_handler_spec.rb +1 -1
- data/spec/flydata/source_mysql/plugin_support/shared_query_handler_context.rb +12 -11
- data/spec/flydata/source_mysql/plugin_support/source_position_file_spec.rb +53 -0
- data/spec/flydata/source_mysql/plugin_support/truncate_query_handler_spec.rb +1 -1
- data/spec/flydata/source_mysql/table_ddl_spec.rb +5 -5
- data/spec/flydata/source_mysql/{plugin_support/table_meta_spec.rb → table_meta_spec.rb} +6 -7
- data/spec/flydata/source_postgresql/generate_source_dump_spec.rb +165 -77
- data/spec/flydata/source_postgresql/query_based_sync/diff_query_generator_spec.rb +213 -0
- data/spec/flydata/source_postgresql/query_based_sync/query_based_sync_postgresql_context.rb +76 -0
- data/spec/flydata/source_postgresql/query_based_sync/resource_requester_spec.rb +70 -0
- data/spec/flydata/source_postgresql/table_meta_spec.rb +77 -0
- metadata +49 -6
- data/lib/flydata/source_mysql/plugin_support/binlog_position_file.rb +0 -23
- data/lib/flydata/source_postgresql/pg_client.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b335ff2222169fc42a78d4dec2a5829aa0c94230
|
4
|
+
data.tar.gz: 15042a74de15a15b3784c6917973154d1ddd02c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86fb1aa9fe1449e11f0d8755773cd7a083054bb668df7dbf489973828b018f9ebe2e9a10850bcf8ca7afff7682f157cd7d3a3082907b458ad1b5cbba99cf73b5
|
7
|
+
data.tar.gz: d36c033143bdd9a1b5931d891406ec6dfbaeaeba70cdae08d78c3282ccf55bebbe3125921bec021bbbb9405907a52431ac0f220722fa10f771db421134c7f348
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/flydata-core/Gemfile
CHANGED
data/flydata-core/Gemfile.lock
CHANGED
@@ -17,6 +17,7 @@ GEM
|
|
17
17
|
parser (2.2.0.pre.8)
|
18
18
|
ast (>= 1.1, < 3.0)
|
19
19
|
slop (~> 3.4, >= 3.4.5)
|
20
|
+
pg (0.18.4)
|
20
21
|
powerpack (0.0.9)
|
21
22
|
rainbow (2.0.0)
|
22
23
|
rspec (3.1.0)
|
@@ -54,8 +55,12 @@ PLATFORMS
|
|
54
55
|
DEPENDENCIES
|
55
56
|
aws-sdk (= 1.18.0)
|
56
57
|
mysql2
|
58
|
+
pg
|
57
59
|
rspec (~> 3.1)
|
58
60
|
rubocop
|
59
61
|
ruby-prof
|
60
62
|
simplecov
|
61
63
|
timecop
|
64
|
+
|
65
|
+
BUNDLED WITH
|
66
|
+
1.10.6
|
@@ -317,12 +317,14 @@ end
|
|
317
317
|
class CompatibilityError < StandardError
|
318
318
|
end
|
319
319
|
|
320
|
-
class AgentCompatibilityError <
|
320
|
+
class AgentCompatibilityError < CompatibilityError
|
321
321
|
end
|
322
322
|
|
323
|
-
class MysqlCompatibilityError <
|
323
|
+
class MysqlCompatibilityError < CompatibilityError
|
324
324
|
end
|
325
325
|
|
326
|
+
class PostgresqlCompatibilityError < CompatibilityError
|
327
|
+
end
|
326
328
|
|
327
329
|
## Error container
|
328
330
|
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'flydata-core/errors'
|
2
|
+
require 'flydata-core/postgresql/config'
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
module FlydataCore
|
6
|
+
module Postgresql
|
7
|
+
class CompatibilityChecker
|
8
|
+
def initialize(option = {})
|
9
|
+
option ||= {}
|
10
|
+
@option = option.merge FlydataCore::Postgresql::Config.build_db_opts(option)
|
11
|
+
end
|
12
|
+
|
13
|
+
def do_check(option = @option, &block)
|
14
|
+
result = block.call create_query(option)
|
15
|
+
check_result(result, option)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Override
|
19
|
+
#def create_query(option = @option)
|
20
|
+
#end
|
21
|
+
|
22
|
+
# Override
|
23
|
+
#def validate_result(result, option = @option)
|
24
|
+
#end
|
25
|
+
end
|
26
|
+
|
27
|
+
class PostgresqlCompatibilityChecker < CompatibilityChecker
|
28
|
+
def do_check(option = @option, &block)
|
29
|
+
query = create_query(option)
|
30
|
+
result = if block
|
31
|
+
block.call query
|
32
|
+
else
|
33
|
+
exec_query(query)
|
34
|
+
end
|
35
|
+
check_result(result, option)
|
36
|
+
end
|
37
|
+
|
38
|
+
def exec_query(query)
|
39
|
+
begin
|
40
|
+
client = PGconn.connect(FlydataCore::Postgresql::Config.opts_for_pg(@option))
|
41
|
+
client.exec(query)
|
42
|
+
ensure
|
43
|
+
client.close rescue nil if client
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def schema_and_table_in_query(option = @option)
|
48
|
+
schema = if option[:schema].to_s.strip.empty?
|
49
|
+
"select current_schema"
|
50
|
+
else
|
51
|
+
"'#{option[:schema]}'"
|
52
|
+
end
|
53
|
+
{
|
54
|
+
schema_name: schema,
|
55
|
+
table_names: option[:tables].collect{|tn| "'#{tn}'"}.join(',')
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class TableExistenceChecker < PostgresqlCompatibilityChecker
|
61
|
+
TABLE_EXISTENCE_CHECK_QUERY_TMPLT = <<EOT
|
62
|
+
SELECT
|
63
|
+
table_name
|
64
|
+
FROM
|
65
|
+
information_schema.tables
|
66
|
+
WHERE
|
67
|
+
table_schema in (%{schema_name})
|
68
|
+
AND
|
69
|
+
table_name in (%{table_names});
|
70
|
+
EOT
|
71
|
+
|
72
|
+
def create_query(option = @option)
|
73
|
+
TABLE_EXISTENCE_CHECK_QUERY_TMPLT % schema_and_table_in_query(option)
|
74
|
+
end
|
75
|
+
|
76
|
+
def check_result(result, option = @option)
|
77
|
+
existing_tables = []
|
78
|
+
result.each {|r| existing_tables << r['table_name']}
|
79
|
+
missing_tables = option[:tables] - existing_tables
|
80
|
+
|
81
|
+
unless missing_tables.empty?
|
82
|
+
raise FlydataCore::PostgresqlCompatibilityError,
|
83
|
+
"These tables are missing. Create these tables on your database or remove them from the data entry : #{missing_tables.join(", ")}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class PrimaryKeyChecker < PostgresqlCompatibilityChecker
|
89
|
+
PK_CHECK_QUERY_TMPLT = <<EOT
|
90
|
+
SELECT
|
91
|
+
t.table_name
|
92
|
+
FROM
|
93
|
+
(select * from information_schema.tables where table_schema in (%{schema_name}) AND table_name in (%{table_names})) t
|
94
|
+
LEFT OUTER JOIN
|
95
|
+
(select * from information_schema.table_constraints where table_schema in (%{schema_name}) AND table_name in (%{table_names})) tc
|
96
|
+
USING (table_schema, table_name)
|
97
|
+
GROUP BY
|
98
|
+
t.table_schema, t.table_name
|
99
|
+
HAVING
|
100
|
+
SUM(CASE WHEN tc.constraint_type='PRIMARY KEY' THEN 1 ELSE 0 END) = 0;
|
101
|
+
EOT
|
102
|
+
|
103
|
+
def create_query(option = @option)
|
104
|
+
PK_CHECK_QUERY_TMPLT % schema_and_table_in_query(option)
|
105
|
+
end
|
106
|
+
|
107
|
+
def check_result(result, option = @option)
|
108
|
+
missing_pk_tables = []
|
109
|
+
result.each {|r| missing_pk_tables << r['table_name']}
|
110
|
+
|
111
|
+
unless missing_pk_tables.empty?
|
112
|
+
raise FlydataCore::PostgresqlCompatibilityError,
|
113
|
+
"Primary key is required for tables to sync. " +
|
114
|
+
"Add primary key or remove following tables from data entry: #{missing_pk_tables.join(", ")}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module FlydataCore
|
2
|
+
module Postgresql
|
3
|
+
class Config
|
4
|
+
def self.build_db_opts(db_conf)
|
5
|
+
db_opts = [:host,
|
6
|
+
:port,
|
7
|
+
:username,
|
8
|
+
:password,
|
9
|
+
:database,
|
10
|
+
:dbname,
|
11
|
+
:user,
|
12
|
+
:connect_timeout,
|
13
|
+
:sslmode,
|
14
|
+
:options,
|
15
|
+
].inject({}) { |h, sym|
|
16
|
+
if db_conf.has_key?(sym)
|
17
|
+
h[sym] = db_conf[sym]
|
18
|
+
elsif db_conf[sym.to_s]
|
19
|
+
h[sym] = db_conf[sym.to_s]
|
20
|
+
end
|
21
|
+
h
|
22
|
+
}
|
23
|
+
|
24
|
+
# for pg gem
|
25
|
+
update_opts(db_opts, :user, :username)
|
26
|
+
update_opts(db_opts, :dbname, :database)
|
27
|
+
|
28
|
+
db_opts
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns options for making pg connection
|
32
|
+
# pg does not accept unsupported keys
|
33
|
+
# http://www.rubydoc.info/gems/pg/PG%2FConnection%3Ainitialize
|
34
|
+
def self.opts_for_pg(db_conf)
|
35
|
+
db_opts = build_db_opts(db_conf)
|
36
|
+
|
37
|
+
[:host,
|
38
|
+
:port,
|
39
|
+
:user,
|
40
|
+
:password,
|
41
|
+
:dbname,
|
42
|
+
:connect_timeout,
|
43
|
+
:sslmode,
|
44
|
+
:options,
|
45
|
+
].inject({}) do |ret, k|
|
46
|
+
ret[k] = db_opts[k] if db_opts[k]
|
47
|
+
ret
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.update_opts(opts, dst_key, src_key)
|
52
|
+
if opts[dst_key].nil? && opts[src_key]
|
53
|
+
opts[dst_key] = opts[src_key]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'pg'
|
2
|
+
require 'socket'
|
3
|
+
require 'delegate'
|
4
|
+
require 'flydata-core/postgresql/config'
|
5
|
+
|
6
|
+
module FlydataCore
|
7
|
+
module Postgresql
|
8
|
+
|
9
|
+
class PGClient
|
10
|
+
PG_CONNECT_TIMEOUT = 10.0
|
11
|
+
|
12
|
+
def initialize(dbconf)
|
13
|
+
@dbconf = FlydataCore::Postgresql::Config.opts_for_pg(dbconf)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :dbconf
|
17
|
+
|
18
|
+
def establish_connection
|
19
|
+
@conn = create_connection if @conn.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def query(query, params = [])
|
23
|
+
establish_connection
|
24
|
+
|
25
|
+
if query.respond_to?(:placeholder_start_num) && query.placeholder_start_num
|
26
|
+
placeholders = placeholder_string(query.placeholder_size,
|
27
|
+
query.placeholder_start_num)
|
28
|
+
q = query % [placeholders]
|
29
|
+
else
|
30
|
+
q = query
|
31
|
+
end
|
32
|
+
|
33
|
+
if (params.nil? || params.empty?) && query.respond_to?(:binding_params)
|
34
|
+
params = query.binding_params || []
|
35
|
+
end
|
36
|
+
|
37
|
+
result = @conn.query(q, params)
|
38
|
+
|
39
|
+
query.respond_to?(:value_overriders) && query.value_overriders ?
|
40
|
+
EnumerableDelegator.new(result, HashValueOverrider, query.value_overriders)
|
41
|
+
: result
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
if @conn
|
46
|
+
@conn.finish
|
47
|
+
@conn = nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def create_connection
|
54
|
+
conn = nil
|
55
|
+
retry_on(Errno::EBADF, 3) do
|
56
|
+
hostaddr = IPSocket.getaddress(dbconf[:host])
|
57
|
+
dbconf[:hostaddr] = hostaddr
|
58
|
+
conn = PG::Connection.connect_start(dbconf)
|
59
|
+
raise PG::Error.new("Unable to create a new connection.") unless conn
|
60
|
+
raise PG::Error.new("Connection failed: %s" % [ conn.error_message ]) if conn.status == PG::CONNECTION_BAD
|
61
|
+
|
62
|
+
socket = conn.socket_io
|
63
|
+
poll_status = PG::PGRES_POLLING_WRITING
|
64
|
+
until poll_status == PG::PGRES_POLLING_OK || poll_status == PG::PGRES_POLLING_FAILED
|
65
|
+
case poll_status
|
66
|
+
when PG::PGRES_POLLING_READING
|
67
|
+
IO.select([socket], nil, nil, PG_CONNECT_TIMEOUT) or raise PG::Error.new("Asynchronous connection timed out!(READING)")
|
68
|
+
when PG::PGRES_POLLING_WRITING
|
69
|
+
IO.select(nil, [socket], nil, PG_CONNECT_TIMEOUT) or raise PG::Error.new("Asynchronous connection timed out!(WRITING)")
|
70
|
+
end
|
71
|
+
poll_status = conn.connect_poll
|
72
|
+
end
|
73
|
+
end
|
74
|
+
unless conn.status == PG::CONNECTION_OK
|
75
|
+
raise PG::Error.new("Connect failed: %s" % [ conn.error_message.to_s.lines.uniq.join(" ") ])
|
76
|
+
end
|
77
|
+
conn
|
78
|
+
rescue Errno::EBADF => e
|
79
|
+
raise PG::Error.new("Failed to connect redshift due to Errno::EBADF. #{e.to_s}")
|
80
|
+
rescue SocketError => e
|
81
|
+
if e.to_s == 'getaddrinfo: nodename nor servname provided, or not known'
|
82
|
+
raise PG::Error.new("Connection failed: FATAL: unknown host(#{dbconf[:host]}).")
|
83
|
+
end
|
84
|
+
raise e
|
85
|
+
end
|
86
|
+
|
87
|
+
# Retry the given block if +exception+ happens
|
88
|
+
def retry_on(exception = StandardError, try_count = 3, interval = 1.0)
|
89
|
+
count = 0
|
90
|
+
begin
|
91
|
+
count += 1
|
92
|
+
yield
|
93
|
+
rescue exception
|
94
|
+
if count < try_count
|
95
|
+
sleep interval
|
96
|
+
interval *= 2
|
97
|
+
retry
|
98
|
+
else
|
99
|
+
raise
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def placeholder_string(num_items, start_num)
|
105
|
+
num_items.times.collect{|i| "$#{i + start_num}"}.join(",")
|
106
|
+
end
|
107
|
+
|
108
|
+
class EnumerableDelegator
|
109
|
+
include Enumerable
|
110
|
+
|
111
|
+
def initialize(delegate, item_delegator_class, *args)
|
112
|
+
@delegate = delegate
|
113
|
+
@item_delegator_class = item_delegator_class
|
114
|
+
@args = args
|
115
|
+
end
|
116
|
+
|
117
|
+
def each(&block)
|
118
|
+
@delegate.each do |item|
|
119
|
+
block.call(@item_delegator_class.new(item, *@args))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class HashValueOverrider < SimpleDelegator
|
125
|
+
def initialize(delegate, overriders)
|
126
|
+
super(delegate)
|
127
|
+
@overriders = overriders
|
128
|
+
end
|
129
|
+
|
130
|
+
def [](key)
|
131
|
+
val = __getobj__[key]
|
132
|
+
override(key, val)
|
133
|
+
end
|
134
|
+
|
135
|
+
# TODO: all methods returning hash value(s) must be overridden
|
136
|
+
|
137
|
+
def first
|
138
|
+
key, val = __getobj__.first
|
139
|
+
[key, override(key, val)]
|
140
|
+
end
|
141
|
+
|
142
|
+
def values
|
143
|
+
__getobj__.keys.collect{|k| override(k, __getobj__[k]) }
|
144
|
+
end
|
145
|
+
|
146
|
+
def kind_of?(klass)
|
147
|
+
__getobj__.kind_of?(klass)
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def override(key, val)
|
153
|
+
@overriders.has_key?(key) ? @overriders[key].call(val) : val
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class PGQuery < SimpleDelegator
|
159
|
+
def initialize(query_text, opts)
|
160
|
+
super(query_text)
|
161
|
+
@value_overriders = opts[:value_overriders]
|
162
|
+
@placeholder_start_num = opts[:placeholder_start_num]
|
163
|
+
@placeholder_size = opts[:placeholder_size]
|
164
|
+
@binding_params = opts[:binding_params]
|
165
|
+
end
|
166
|
+
attr_reader :value_overriders, :placeholder_start_num, :placeholder_size, :binding_params
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Snapshot components
|
2
|
+
# http://www.postgresql.org/docs/8.3/static/functions-info.html#FUNCTIONS-TXID-SNAPSHOT-PARTS
|
3
|
+
#
|
4
|
+
# Example) 10:20:10,14,15 means xmin=10, xmax=20, xip_list=10, 14, 15.
|
5
|
+
|
6
|
+
module FlydataCore
|
7
|
+
module Postgresql
|
8
|
+
|
9
|
+
class Snapshot
|
10
|
+
include Comparable
|
11
|
+
|
12
|
+
def initialize(txid_snapshot)
|
13
|
+
@txid_snapshot_str = txid_snapshot.to_s
|
14
|
+
xmin_str, xmax_str, xip_list_str = @txid_snapshot_str.split(':')
|
15
|
+
|
16
|
+
raise ArgumentError, "Invalid snapshot - xmin is empty." if xmin_str.to_s.empty?
|
17
|
+
raise ArgumentError, "Invalid snapshot - xmax is empty." if xmax_str.to_s.empty?
|
18
|
+
|
19
|
+
@xmin = xmin_str.to_i
|
20
|
+
@xmax = xmax_str.to_i
|
21
|
+
@xip_list = xip_list_str.to_s.split(',').collect(&:to_i)
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :xmin, :xmax, :xip_list
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
@txid_snapshot_str
|
28
|
+
end
|
29
|
+
|
30
|
+
def <=>(other)
|
31
|
+
if @xmin == other.xmin
|
32
|
+
if @xmax == other.xmax
|
33
|
+
# items xip_list will disappear after the transaction is completed,
|
34
|
+
# because xip_list is an active transaction list.
|
35
|
+
#
|
36
|
+
# The following comparison needs to be true
|
37
|
+
# "10:18:10,11,12" < "10:18:11,12"
|
38
|
+
(other.xip_list.size <=> @xip_list.size)
|
39
|
+
else
|
40
|
+
@xmax <=> other.xmax
|
41
|
+
end
|
42
|
+
else
|
43
|
+
@xmin <=> other.xmin
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|