summaryrefslogtreecommitdiff
path: root/db/post_migrate/20180223124427_build_user_contributed_projects_table.rb
blob: 40049d4ab650091cecb225a15fee44c96ae270d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class BuildUserContributedProjectsTable < ActiveRecord::Migration
  include Gitlab::Database::MigrationHelpers

  # Set this constant to true if this migration requires downtime.
  DOWNTIME = false

  disable_ddl_transaction!

  def up
    if Gitlab::Database.postgresql?
      PostgresStrategy.new
    else
      MysqlStrategy.new
    end.up
  end

  def down
    execute "TRUNCATE user_contributed_projects"
  end

  private

  class PostgresStrategy < ActiveRecord::Migration
    include Gitlab::Database::MigrationHelpers

    BATCH_SIZE = 100_000
    SLEEP_TIME = 30

    def up
      with_index(:events, [:author_id, :project_id], name: 'events_user_contributions_temp', where: 'project_id IS NOT NULL') do
        iteration = 0
        records = 0
        begin
          Rails.logger.info "Building user_contributed_projects table, batch ##{iteration}"
          result = execute <<~SQL
            INSERT INTO user_contributed_projects (user_id, project_id)
            SELECT e.user_id, e.project_id
            FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
            LEFT JOIN user_contributed_projects ucp USING (user_id, project_id)
            WHERE ucp.user_id IS NULL
            LIMIT #{BATCH_SIZE}
          SQL
          iteration += 1
          records += result.cmd_tuples
          Rails.logger.info "Building user_contributed_projects table, batch ##{iteration} complete, created #{records} overall"
          Kernel.sleep(SLEEP_TIME) if result.cmd_tuples > 0
        end while result.cmd_tuples > 0
      end

      execute "ANALYZE user_contributed_projects"
    end

    private

    def with_index(*args)
      add_concurrent_index(*args) unless index_exists?(*args)
      yield
    ensure
      remove_concurrent_index(*args) if index_exists?(*args)
    end
  end

  class MysqlStrategy < ActiveRecord::Migration
    include Gitlab::Database::MigrationHelpers

    def up
      execute <<~SQL
        INSERT INTO user_contributed_projects (user_id, project_id)
        SELECT e.user_id, e.project_id
        FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
        LEFT JOIN user_contributed_projects ucp USING (user_id, project_id)
        WHERE ucp.user_id IS NULL
      SQL
    end
  end

end