Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
cbc50b76
Commit
cbc50b76
authored
Dec 06, 2021
by
Heinrich Lee Yu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Optimize query for issue neighbors
Fixes query timeouts when ordering issues in issue boards Changelog: fixed
parent
43a6b985
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
84 additions
and
22 deletions
+84
-22
app/models/concerns/relative_positioning.rb
app/models/concerns/relative_positioning.rb
+18
-0
app/models/issue.rb
app/models/issue.rb
+30
-2
config/feature_flags/development/optimized_issue_neighbor_queries.yml
...re_flags/development/optimized_issue_neighbor_queries.yml
+8
-0
lib/gitlab/relative_positioning/item_context.rb
lib/gitlab/relative_positioning/item_context.rb
+6
-16
spec/models/issue_spec.rb
spec/models/issue_spec.rb
+22
-4
No files found.
app/models/concerns/relative_positioning.rb
View file @
cbc50b76
...
...
@@ -168,6 +168,24 @@ module RelativePositioning
self
.
relative_position
=
MIN_POSITION
end
def
next_object_by_relative_position
(
ignoring:
nil
,
order: :asc
)
relation
=
relative_positioning_scoped_items
(
ignoring:
ignoring
).
reorder
(
relative_position:
order
)
relation
=
if
order
==
:asc
relation
.
where
(
self
.
class
.
arel_table
[
:relative_position
].
gt
(
relative_position
))
else
relation
.
where
(
self
.
class
.
arel_table
[
:relative_position
].
lt
(
relative_position
))
end
relation
.
first
end
def
relative_positioning_scoped_items
(
ignoring:
nil
)
relation
=
self
.
class
.
relative_positioning_query_base
(
self
)
relation
=
exclude_self
(
relation
,
excluded:
ignoring
)
if
ignoring
.
present?
relation
end
# This method is used during rebalancing - override it to customise the update
# logic:
def
update_relative_siblings
(
relation
,
range
,
delta
)
...
...
app/models/issue.rb
View file @
cbc50b76
...
...
@@ -229,9 +229,37 @@ class Issue < ApplicationRecord
end
end
def
next_object_by_relative_position
(
ignoring:
nil
,
order: :asc
)
return
super
unless
Feature
.
enabled?
(
:optimized_issue_neighbor_queries
,
project
,
default_enabled: :yaml
)
array_mapping_scope
=
->
(
id_expression
)
do
relation
=
Issue
.
where
(
Issue
.
arel_table
[
:project_id
].
eq
(
id_expression
))
if
order
==
:asc
relation
.
where
(
Issue
.
arel_table
[
:relative_position
].
gt
(
relative_position
))
else
relation
.
where
(
Issue
.
arel_table
[
:relative_position
].
lt
(
relative_position
))
end
end
relation
=
Gitlab
::
Pagination
::
Keyset
::
InOperatorOptimization
::
QueryBuilder
.
new
(
scope:
Issue
.
order
(
relative_position:
order
,
id:
order
),
array_scope:
relative_positioning_parent_projects
,
array_mapping_scope:
array_mapping_scope
,
finder_query:
->
(
_
,
id_expression
)
{
Issue
.
where
(
Issue
.
arel_table
[
:id
].
eq
(
id_expression
))
}
).
execute
relation
=
exclude_self
(
relation
,
excluded:
ignoring
)
if
ignoring
.
present?
relation
.
take
end
def
relative_positioning_parent_projects
project
.
group
&
.
root_ancestor
&
.
all_projects
&
.
select
(
:id
)
||
Project
.
id_in
(
project
).
select
(
:id
)
end
def
self
.
relative_positioning_query_base
(
issue
)
projects
=
issue
.
project
.
group
&
.
root_ancestor
&
.
all_projects
||
issue
.
project
in_projects
(
projects
)
in_projects
(
issue
.
relative_positioning_parent_projects
)
end
def
self
.
relative_positioning_parent_column
...
...
config/feature_flags/development/optimized_issue_neighbor_queries.yml
0 → 100644
View file @
cbc50b76
---
name
:
optimized_issue_neighbor_queries
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76073
rollout_issue_url
:
https://gitlab.com/gitlab-org/gitlab/-/issues/345921
milestone
:
'
14.6'
type
:
development
group
:
group::project management
default_enabled
:
false
lib/gitlab/relative_positioning/item_context.rb
View file @
cbc50b76
...
...
@@ -66,19 +66,11 @@ module Gitlab
end
def
lhs_neighbour
scoped_items
.
where
(
'relative_position < ?'
,
relative_position
)
.
reorder
(
relative_position: :desc
)
.
first
.
then
{
|
x
|
neighbour
(
x
)
}
neighbour
(
object
.
next_object_by_relative_position
(
ignoring:
ignoring
,
order: :desc
))
end
def
rhs_neighbour
scoped_items
.
where
(
'relative_position > ?'
,
relative_position
)
.
reorder
(
relative_position: :asc
)
.
first
.
then
{
|
x
|
neighbour
(
x
)
}
neighbour
(
object
.
next_object_by_relative_position
(
ignoring:
ignoring
,
order: :asc
))
end
def
neighbour
(
item
)
...
...
@@ -87,12 +79,6 @@ module Gitlab
self
.
class
.
new
(
item
,
range
,
ignoring:
ignoring
)
end
def
scoped_items
r
=
model_class
.
relative_positioning_query_base
(
object
)
r
=
object
.
exclude_self
(
r
,
excluded:
ignoring
)
if
ignoring
.
present?
r
end
def
calculate_relative_position
(
calculation
)
# When calculating across projects, this is much more efficient than
# MAX(relative_position) without the GROUP BY, due to index usage:
...
...
@@ -186,6 +172,10 @@ module Gitlab
Gap
.
new
(
gap
.
first
,
gap
.
second
||
default_end
)
end
def
scoped_items
object
.
relative_positioning_scoped_items
(
ignoring:
ignoring
)
end
def
relative_position
object
.
relative_position
end
...
...
spec/models/issue_spec.rb
View file @
cbc50b76
...
...
@@ -1317,11 +1317,29 @@ RSpec.describe Issue do
let_it_be
(
:issue1
)
{
create
(
:issue
,
project:
project
,
relative_position:
nil
)
}
let_it_be
(
:issue2
)
{
create
(
:issue
,
project:
project
,
relative_position:
nil
)
}
context
'when optimized_issue_neighbor_queries is enabled'
do
before
do
stub_feature_flags
(
optimized_issue_neighbor_queries:
true
)
end
it_behaves_like
"a class that supports relative positioning"
do
let_it_be
(
:project
)
{
reusable_project
}
let
(
:factory
)
{
:issue
}
let
(
:default_params
)
{
{
project:
project
}
}
end
end
context
'when optimized_issue_neighbor_queries is disabled'
do
before
do
stub_feature_flags
(
optimized_issue_neighbor_queries:
false
)
end
it_behaves_like
"a class that supports relative positioning"
do
let_it_be
(
:project
)
{
reusable_project
}
let
(
:factory
)
{
:issue
}
let
(
:default_params
)
{
{
project:
project
}
}
end
end
it
'is not blocked for repositioning by default'
do
expect
(
issue1
.
blocked_for_repositioning?
).
to
eq
(
false
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment