diff options
author | Yorick Peterse <yorickpeterse@gmail.com> | 2017-06-08 18:39:32 +0200 |
---|---|---|
committer | Yorick Peterse <yorickpeterse@gmail.com> | 2017-06-27 15:59:50 +0200 |
commit | 2bda45ebba948d28a70456ec00e9fe3fe882b8a0 (patch) | |
tree | 57f26980dac71717bacf9d1adb72ce4275dcb710 /lib | |
parent | 4503240abdd9a38e801aef49edad9ff9c7f9457d (diff) | |
download | gitlab-ce-split-events-into-push-events.tar.gz |
Use a separate table for storing push eventssplit-events-into-push-events
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gitlab/background_migration/migrate_events_to_push_events.rb | 178 | ||||
-rw-r--r-- | lib/gitlab/database/sha_attribute.rb | 34 |
2 files changed, 212 insertions, 0 deletions
diff --git a/lib/gitlab/background_migration/migrate_events_to_push_events.rb b/lib/gitlab/background_migration/migrate_events_to_push_events.rb new file mode 100644 index 00000000000..5744789183b --- /dev/null +++ b/lib/gitlab/background_migration/migrate_events_to_push_events.rb @@ -0,0 +1,178 @@ +module Gitlab + module BackgroundMigration + # Class for migrating push events from the "events" table into the + # "push_events" table. + class MigrateEventsToPushEvents + class Event < ActiveRecord::Base + self.table_name = 'events' + + serialize :data # rubocop:disable Cop/ActiverecordSerialize + + BLANK_REF = ('0' * 40).freeze + TAG_REF_PREFIX = 'refs/tags/'.freeze + MAX_INDEX = 69 + + def commit_summary + commit = commits.last + + return nil unless commit + + index = commit[:message].index("\n") || MAX_INDEX + index = MAX_INDEX if index > MAX_INDEX + + commit[:message][0..index].strip + end + + def first_commit_sha + if commits? + commits.first[:id] + elsif create? + nil + else + data[:before] + end + end + + def last_commit_sha + if commits? + commits.last[:id] + elsif remove? + nil + else + data[:after] + end + end + + def commits? + commits.any? + end + + def commits + data[:commits] + end + + def commit_count + data[:total_commits_count] + end + + def ref + data[:ref] + end + + def trimmed_ref_name + if ref_type == :tag + ref[10..-1] + else + ref[11..-1] + end + end + + def create? + data[:before] == BLANK_REF + end + + def remove? + data[:after] == BLANK_REF + end + + def push_action + if create? + :created + elsif remove? + :removed + else + :pushed + end + end + + def ref_type + if ref.start_with?(TAG_REF_PREFIX) + :tag + else + :branch + end + end + end + + class PushEvent < ActiveRecord::Base + self.table_name = 'push_events' + + enum action: { + created: 0, + removed: 1, + pushed: 2 + } + + enum ref_type: { + branch: 0, + tag: 1 + } + end + + # id - The ID of the row in the "events" table to migrate. + def perform(id) + unless migrate? + Rails.logger + .info("Not migrating event #{id} as the events or push_events table does not exist") + + return + end + + event = find_event(id) + + # If the event was removed in the mean time we just skip it. + unless event + Rails.logger + .info("Not migrating event #{id} as the row no longer exists") + + return + end + + create_push_event(event) + end + + def create_push_event(event) + first_commit = pack(event.first_commit_sha) + last_commit = pack(event.last_commit_sha) + + begin + PushEvent.create!( + created_at: event.created_at, + user_id: event.author_id, + project_id: event.project_id, + commit_count: event.commit_count, + ref_type: event.ref_type, + action: event.push_action, + first_commit: first_commit, + last_commit: last_commit, + ref: event.trimmed_ref_name, + commit_message: event.commit_summary + ) + rescue ActiveRecord::InvalidForeignKey => error + # If the user or project no longer exists we'll also skip migrating + # the event. + Rails.logger + .info("Not migrating event #{event.id} due to a foreign key error: #{error.message}") + + return + end + + event.destroy! + end + + def find_event(id) + Event + .select([:id, :data, :project_id, :created_at, :author_id]) + .find_by(id: id) + end + + def migrate? + Event.table_exists? && PushEvent.table_exists? + end + + def pack(value) + value ? [value].pack('H*') : nil + end + end + end +end diff --git a/lib/gitlab/database/sha_attribute.rb b/lib/gitlab/database/sha_attribute.rb new file mode 100644 index 00000000000..d9400e04b83 --- /dev/null +++ b/lib/gitlab/database/sha_attribute.rb @@ -0,0 +1,34 @@ +module Gitlab + module Database + BINARY_TYPE = if Gitlab::Database.postgresql? + # PostgreSQL defines its own class with slightly different + # behaviour from the default Binary type. + ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea + else + ActiveRecord::Type::Binary + end + + # Class for casting binary data to hexadecimal SHA1 hashes (and vice-versa). + # + # Using ShaAttribute allows you to store SHA1 values as binary while still + # using them as if they were stored as string values. This gives you the + # ease of use of string values, but without the storage overhead. + class ShaAttribute < BINARY_TYPE + PACK_FORMAT = 'H*'.freeze + + # Casts binary data to a SHA1 in hexadecimal. + def type_cast_from_database(value) + value = super + + value ? value.unpack(PACK_FORMAT)[0] : nil + end + + # Casts a SHA1 in hexadecimal to the proper binary format. + def type_cast_for_database(value) + arg = value ? [value].pack(PACK_FORMAT) : nil + + super(arg) + end + end + end +end |