Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/database/transaction/context.rb')
-rw-r--r--lib/gitlab/database/transaction/context.rb125
1 files changed, 125 insertions, 0 deletions
diff --git a/lib/gitlab/database/transaction/context.rb b/lib/gitlab/database/transaction/context.rb
new file mode 100644
index 00000000000..a50dd30b75b
--- /dev/null
+++ b/lib/gitlab/database/transaction/context.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Transaction
+ class Context
+ attr_reader :context
+
+ LOG_DEPTH_THRESHOLD = 8
+ LOG_SAVEPOINTS_THRESHOLD = 32
+ LOG_DURATION_S_THRESHOLD = 300
+ LOG_THROTTLE_DURATION = 1
+
+ def initialize
+ @context = {}
+ end
+
+ def set_start_time
+ @context[:start_time] = current_timestamp
+ end
+
+ def increment_savepoints
+ @context[:savepoints] = @context[:savepoints].to_i + 1
+ end
+
+ def increment_rollbacks
+ @context[:rollbacks] = @context[:rollbacks].to_i + 1
+ end
+
+ def increment_releases
+ @context[:releases] = @context[:releases].to_i + 1
+ end
+
+ def set_depth(depth)
+ @context[:depth] = [@context[:depth].to_i, depth].max
+ end
+
+ def track_sql(sql)
+ (@context[:queries] ||= []).push(sql)
+ end
+
+ def duration
+ return unless @context[:start_time].present?
+
+ current_timestamp - @context[:start_time]
+ end
+
+ def depth_threshold_exceeded?
+ @context[:depth].to_i > LOG_DEPTH_THRESHOLD
+ end
+
+ def savepoints_threshold_exceeded?
+ @context[:savepoints].to_i > LOG_SAVEPOINTS_THRESHOLD
+ end
+
+ def duration_threshold_exceeded?
+ duration.to_i > LOG_DURATION_S_THRESHOLD
+ end
+
+ def log_savepoints?
+ depth_threshold_exceeded? || savepoints_threshold_exceeded?
+ end
+
+ def log_duration?
+ duration_threshold_exceeded?
+ end
+
+ def should_log?
+ !logged_already? && (log_savepoints? || log_duration?)
+ end
+
+ def commit
+ log(:commit)
+ end
+
+ def rollback
+ log(:rollback)
+ end
+
+ private
+
+ def queries
+ @context[:queries].to_a.join("\n")
+ end
+
+ def current_timestamp
+ ::Gitlab::Metrics::System.monotonic_time
+ end
+
+ def logged_already?
+ return false if @context[:last_log_timestamp].nil?
+
+ (current_timestamp - @context[:last_log_timestamp].to_i) < LOG_THROTTLE_DURATION
+ end
+
+ def set_last_log_timestamp
+ @context[:last_log_timestamp] = current_timestamp
+ end
+
+ def log(operation)
+ return unless should_log?
+
+ set_last_log_timestamp
+
+ attributes = {
+ class: self.class.name,
+ result: operation,
+ duration_s: duration,
+ depth: @context[:depth].to_i,
+ savepoints_count: @context[:savepoints].to_i,
+ rollbacks_count: @context[:rollbacks].to_i,
+ releases_count: @context[:releases].to_i,
+ sql: queries
+ }
+
+ application_info(attributes)
+ end
+
+ def application_info(attributes)
+ Gitlab::AppJsonLogger.info(attributes)
+ end
+ end
+ end
+ end
+end