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/ci/trace/checksum.rb')
-rw-r--r--lib/gitlab/ci/trace/checksum.rb83
1 files changed, 83 insertions, 0 deletions
diff --git a/lib/gitlab/ci/trace/checksum.rb b/lib/gitlab/ci/trace/checksum.rb
new file mode 100644
index 00000000000..62532ef1cd2
--- /dev/null
+++ b/lib/gitlab/ci/trace/checksum.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Trace
+ ##
+ # Trace::Checksum class is responsible for calculating a CRC32 checksum
+ # of an entire build trace using partial build trace chunks stored in a
+ # database.
+ #
+ # CRC32 checksum can be easily calculated by combining partial checksums
+ # in a right order.
+ #
+ # Then we compare CRC32 checksum provided by a GitLab Runner and expect
+ # it to be the same as the CRC32 checksum derived from partial chunks.
+ #
+ class Checksum
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :build
+
+ def initialize(build)
+ @build = build
+ end
+
+ def valid?
+ return false unless state_crc32.present?
+
+ state_crc32 == chunks_crc32
+ end
+
+ def state_crc32
+ strong_memoize(:state_crc32) { build.pending_state&.crc32 }
+ end
+
+ def chunks_crc32
+ strong_memoize(:chunks_crc32) do
+ trace_chunks.reduce(0) do |crc32, chunk|
+ Zlib.crc32_combine(crc32, chunk.crc32, chunk_size(chunk))
+ end
+ end
+ end
+
+ def last_chunk
+ strong_memoize(:last_chunk) { trace_chunks.max }
+ end
+
+ ##
+ # Trace chunks will be persisted in a database if an object store is
+ # not configured - in that case we do not want to load entire raw data
+ # of all the chunks into memory.
+ #
+ # We ignore `raw_data` attribute instead, and rely on internal build
+ # trace chunk database adapter to handle
+ # `ActiveModel::MissingAttributeError` exception.
+ #
+ # Alternative solution would be separating chunk data from chunk
+ # metadata on the database level too.
+ #
+ def trace_chunks
+ strong_memoize(:trace_chunks) do
+ build.trace_chunks.persisted
+ .select(::Ci::BuildTraceChunk.metadata_attributes)
+ end
+ end
+
+ def chunks_count
+ trace_chunks.to_a.size
+ end
+
+ private
+
+ def chunk_size(chunk)
+ if chunk == last_chunk
+ chunk.size
+ else
+ ::Ci::BuildTraceChunk::CHUNK_SIZE
+ end
+ end
+ end
+ end
+ end
+end