Class: Namespace::TraversalHierarchy

Inherits:
Object
  • Object
show all
Defined in:
app/models/namespace/traversal_hierarchy.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root) ⇒ TraversalHierarchy

Returns a new instance of TraversalHierarchy.

Raises:

  • (StandardError)


22
23
24
25
26
# File 'app/models/namespace/traversal_hierarchy.rb', line 22

def initialize(root)
  raise StandardError, 'Must specify a root node' if root.parent_id

  @root = root
end

Instance Attribute Details

#rootObject

Returns the value of attribute root.



16
17
18
# File 'app/models/namespace/traversal_hierarchy.rb', line 16

def root
  @root
end

Class Method Details

.for_namespace(namespace) ⇒ Object



18
19
20
# File 'app/models/namespace/traversal_hierarchy.rb', line 18

def self.for_namespace(namespace)
  new(recursive_root_ancestor(namespace))
end

Instance Method Details

#incorrect_traversal_idsObject

Identify all incorrect traversal_ids in the current namespace hierarchy.



59
60
61
62
63
# File 'app/models/namespace/traversal_hierarchy.rb', line 59

def incorrect_traversal_ids
  Namespace
    .joins("INNER JOIN (#{recursive_traversal_ids}) as cte ON namespaces.id = cte.id")
    .where('namespaces.traversal_ids::bigint[] <> cte.traversal_ids')
end

#sync_traversal_ids!Object

Update all traversal_ids in the current namespace hierarchy.



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
# File 'app/models/namespace/traversal_hierarchy.rb', line 29

def sync_traversal_ids!
  # An issue in Rails since 2013 prevents this kind of join based update in
  # ActiveRecord. https://github.com/rails/rails/issues/13496
  # Ideally it would be:
  #   `incorrect_traversal_ids.update_all('traversal_ids = cte.traversal_ids')`
  sql = <<-SQL
    UPDATE namespaces
    SET traversal_ids = cte.traversal_ids
    FROM (#{recursive_traversal_ids}) as cte
    WHERE namespaces.id = cte.id
      AND namespaces.traversal_ids::bigint[] <> cte.traversal_ids
  SQL

  # Hint: when a user is created, it also creates a Namespaces::UserNamespace in
  # `ensure_namespace_correct`. This method is then called within the same
  # transaction of the user INSERT.
  Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
    %w[namespaces], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424279'
  ) do
    Namespace.transaction do
      @root.lock!("FOR NO KEY UPDATE")
      Namespace.connection.exec_query(sql)
    end
  end
rescue ActiveRecord::Deadlocked
  db_deadlock_counter.increment(source: 'Namespace#sync_traversal_ids!')
  raise
end