gamma_replication 0.1.1 → 0.1.2
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/exe/gamma_replication +4 -0
- data/lib/gamma_replication/command/base_replication.rb +94 -5
- data/lib/gamma_replication/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39c63ef1a8906600d9df6b25658cbd4a1b8674be75cb6b5d3d870419f9e5f75e
|
4
|
+
data.tar.gz: ad13bc1e0d79976532f368cd555e59cb89300c920743f35d145b7a928a588ae9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a5aa663b77e7354ff500e7fcb3fe936b103edf466442e8e44b9e31297da5c6dd4eec0ba12472f195490f710ab6d3dbd3a351311e2676d1edd104b73b396752f
|
7
|
+
data.tar.gz: bc597b21d63e0135ffa154116db12acf4578678db85ab9ef090df30e7247d078e1907460f377c4baa0111317ae9dde8e0bbc5ab9e57cbcda68a9288074e5ab6f
|
data/exe/gamma_replication
CHANGED
@@ -12,6 +12,8 @@ class GammaReplicationCLI < Thor
|
|
12
12
|
option :data, aliases: "-d", desc: "Table Sync Settings yaml", required: true
|
13
13
|
option :hook_dir, aliases: "-h", desc: "Hook script directory", default: "."
|
14
14
|
option :maxwell_config, aliases: "-m", desc: "Maxwell configuration file path", required: true
|
15
|
+
option :enable_stats, type: :boolean, desc: "Enable statistics output (default: true)"
|
16
|
+
option :stats_interval, type: :numeric, desc: "Statistics output interval in seconds (default: 10800)"
|
15
17
|
def start
|
16
18
|
GammaReplication::Command::Start.new(options).execute
|
17
19
|
end
|
@@ -21,6 +23,8 @@ class GammaReplicationCLI < Thor
|
|
21
23
|
option :data, aliases: "-d", desc: "Table Sync Settings yaml", required: true
|
22
24
|
option :hook_dir, aliases: "-h", desc: "Hook script directory", default: "."
|
23
25
|
option :maxwell_config, aliases: "-m", desc: "Maxwell configuration file path", required: true
|
26
|
+
option :enable_stats, type: :boolean, desc: "Enable statistics output (default: true)"
|
27
|
+
option :stats_interval, type: :numeric, desc: "Statistics output interval in seconds (default: 10800)"
|
24
28
|
def dryrun
|
25
29
|
GammaReplication::Command::Dryrun.new(options).execute
|
26
30
|
end
|
@@ -8,6 +8,9 @@ module GammaReplication
|
|
8
8
|
setup_database(opts)
|
9
9
|
setup_parser(opts)
|
10
10
|
setup_maxwell(opts)
|
11
|
+
initialize_stats
|
12
|
+
@enable_stats = opts[:enable_stats].nil? ? true : opts[:enable_stats]
|
13
|
+
@stats_interval = (opts[:stats_interval] || 3 * 60 * 60).to_i # Default: 3 hours in seconds
|
11
14
|
end
|
12
15
|
|
13
16
|
def execute
|
@@ -18,6 +21,9 @@ module GammaReplication
|
|
18
21
|
hash[table.table_name] = table
|
19
22
|
end
|
20
23
|
before_start if respond_to?(:before_start)
|
24
|
+
|
25
|
+
setup_stats_reporter if @enable_stats
|
26
|
+
|
21
27
|
@maxwell_client.start do |data|
|
22
28
|
process_maxwell_data(data)
|
23
29
|
end
|
@@ -25,6 +31,52 @@ module GammaReplication
|
|
25
31
|
|
26
32
|
private
|
27
33
|
|
34
|
+
def initialize_stats
|
35
|
+
@stats = {
|
36
|
+
total: { insert: 0, update: 0, delete: 0 },
|
37
|
+
by_table: {}
|
38
|
+
}
|
39
|
+
@stats_mutex = Mutex.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_stats_reporter
|
43
|
+
@stats_thread = Thread.new do
|
44
|
+
loop do
|
45
|
+
sleep @stats_interval
|
46
|
+
output_stats
|
47
|
+
reset_stats
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def update_stats(table_name, operation)
|
53
|
+
return unless @enable_stats
|
54
|
+
|
55
|
+
@stats_mutex.synchronize do
|
56
|
+
@stats[:total][operation] += 1
|
57
|
+
@stats[:by_table][table_name] ||= { insert: 0, update: 0, delete: 0 }
|
58
|
+
@stats[:by_table][table_name][operation] += 1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def reset_stats
|
63
|
+
@stats_mutex.synchronize do
|
64
|
+
initialize_stats
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def output_stats
|
69
|
+
@stats_mutex.synchronize do
|
70
|
+
total_stats = "Total[ins:#{@stats[:total][:insert]} | upd:#{@stats[:total][:update]} | del:#{@stats[:total][:delete]}]"
|
71
|
+
|
72
|
+
table_stats = @stats[:by_table].map do |table, counts|
|
73
|
+
"#{table}[ins:#{counts[:insert]} | upd:#{counts[:update]} | del:#{counts[:delete]}]"
|
74
|
+
end.join("\n")
|
75
|
+
|
76
|
+
logger.info("STATS | #{total_stats}\n#{table_stats}")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
28
80
|
def setup_database(opts)
|
29
81
|
@database_settings = GammaReplication::DatabaseSettings.new(opts[:settings])
|
30
82
|
@in_client = GammaReplication::DatabaseConnector::MysqlConnector.new(@database_settings.in_database)
|
@@ -64,15 +116,23 @@ module GammaReplication
|
|
64
116
|
table_setting = @table_settings[data["table"]]
|
65
117
|
case data["type"]
|
66
118
|
when "insert"
|
119
|
+
return unless data["data"].present?
|
120
|
+
|
121
|
+
update_stats(data["table"], :insert)
|
67
122
|
process_insert(table_setting, data)
|
68
123
|
when "update"
|
124
|
+
return unless data["data"].present?
|
125
|
+
|
126
|
+
update_stats(data["table"], :update)
|
69
127
|
process_update(table_setting, data)
|
70
128
|
when "delete"
|
129
|
+
return unless data["old"].present?
|
130
|
+
|
131
|
+
update_stats(data["table"], :delete)
|
71
132
|
process_delete(table_setting, data)
|
72
133
|
end
|
73
134
|
rescue StandardError => e
|
74
|
-
logger.error(e)
|
75
|
-
# Nothing
|
135
|
+
logger.error("Error processing data: #{data["table"]} - #{e.message}")
|
76
136
|
end
|
77
137
|
|
78
138
|
def process_insert(table_setting, data)
|
@@ -100,8 +160,9 @@ module GammaReplication
|
|
100
160
|
|
101
161
|
def process_delete(table_setting, data)
|
102
162
|
old_record = data["old"]
|
103
|
-
|
163
|
+
return unless old_record.present? && old_record[table_setting.primary_key].present?
|
104
164
|
|
165
|
+
where_clause = build_where_clause(old_record, nil, table_setting.primary_key)
|
105
166
|
query = "DELETE FROM #{table_setting.table_name} WHERE #{where_clause}"
|
106
167
|
execute_query(query)
|
107
168
|
end
|
@@ -120,7 +181,8 @@ module GammaReplication
|
|
120
181
|
elsif new_record.present? && new_record[primary_key].present?
|
121
182
|
"`#{primary_key}` = #{format_value(new_record[primary_key])}"
|
122
183
|
else
|
123
|
-
|
184
|
+
logger.error("Primary key not found. old_record: #{old_record.inspect}, new_record: #{new_record.inspect}")
|
185
|
+
raise "Primary key '#{primary_key}' not found in record"
|
124
186
|
end
|
125
187
|
end
|
126
188
|
|
@@ -133,7 +195,34 @@ module GammaReplication
|
|
133
195
|
when Time
|
134
196
|
"'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
|
135
197
|
else
|
136
|
-
|
198
|
+
if json_column?(value)
|
199
|
+
sanitized_value = sanitize_json(value)
|
200
|
+
"'#{@out_client.client.escape(sanitized_value)}'"
|
201
|
+
else
|
202
|
+
"'#{@out_client.client.escape(value.to_s)}'"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def json_column?(value)
|
208
|
+
value.is_a?(String) && (value.start_with?("{") || value.start_with?("["))
|
209
|
+
end
|
210
|
+
|
211
|
+
def sanitize_json(value)
|
212
|
+
JSON.parse(value)
|
213
|
+
value
|
214
|
+
rescue JSON::ParserError => e
|
215
|
+
sanitized = value.gsub(/([{,]\s*)(\w+)(\s*:)/) do
|
216
|
+
"#{::Regexp.last_match(1)}\"#{::Regexp.last_match(2)}\"#{::Regexp.last_match(3)}"
|
217
|
+
end
|
218
|
+
sanitized = sanitized.gsub(/:\s*([^",\s\d\[\]{}-].*?)(,|\}|$)/) do
|
219
|
+
": \"#{::Regexp.last_match(1)}\"#{::Regexp.last_match(2)}"
|
220
|
+
end
|
221
|
+
begin
|
222
|
+
JSON.parse(sanitized)
|
223
|
+
sanitized
|
224
|
+
rescue JSON::ParserError
|
225
|
+
value.to_json
|
137
226
|
end
|
138
227
|
end
|
139
228
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gamma_replication
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shinsuke Nishio
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|