Skip to content

Conversation

@m1nor
Copy link

@m1nor m1nor commented Aug 4, 2025

Summary

Ticket Link

Screenshots

Release Note


Frank Paul Silye and others added 30 commits June 24, 2024 23:02
Currently translated at 5.7% (332 of 5772 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/
Currently translated at 5.7% (334 of 5772 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/
Currently translated at 100.0% (2509 of 2509 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/
Currently translated at 100.0% (2509 of 2509 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nl/
Currently translated at 100.0% (5772 of 5772 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en_AU/
Currently translated at 6.0% (349 of 5772 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/
Currently translated at 99.9% (2507 of 2509 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/zh_Hans/
Currently translated at 100.0% (5772 of 5772 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hans/
Currently translated at 6.0% (350 of 5772 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/
Currently translated at 100.0% (5772 of 5772 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hans/
Currently translated at 0.9% (24 of 2509 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nb_NO/
Updated by "Cleanup translation files" hook in Weblate.

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/
…most#27421)

* remote users don't get valid email addresses; remote users cannot have access tokens

* block notification emails for remote users

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
* fix overlapping back button

* css tweak

* use classNames utility

* fixed import order
* [skip ci] Support Cloud/daily tests and Zephyr integration

* [skip ci] Fix workflow file

* [skip ci] Fix typo in workflow input name

* Fix cloud variable passing

* [skip ci] Fix typo

* Utilize master branch image for daily tests

* Apply Saturn's suggestion, fixes and improvements
* update for adding multiple members

* fix unit test

* more test fixes

* add another unit test

* fix object passed by client4

* revert package-lock.json

* revert package-lock.json

* add length check

* limit size of lists in API requests

* revert package-lock

* add batching to front end

* add batching to front end

* fix bad merge

* update return type

* remove unnecessary permisssion check, add unit test

* fixes and add tests from review

* revert changes adding limits to other apis

* fixes

* clean-up from code review

* fix unit test call

* revert back to interface{}, fix unit test

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
…o WithTooltip (mattermost#27238)

* Added  console log for draft PR

* Replaced  tooltip  component with changes

* Updated snapshot  for  tests

* Updated  title  to use FormattedMessage

* Remove defineMessages

* Fix style

* Removed unused tooltip

---------

Co-authored-by: ezekiel <ezekiel@itsmart.my>
Co-authored-by: Mattermost Build <build@mattermost.com>
…eview_modal_main_nav/file_preview_modal_main_nav' to WithTooltip (mattermost#27422)
* MM-58755 - Fixing inproduct notices spacing

* Updating compass modal

* Updating test
Running `make i18n-extract` on a en.json file
with bad JSON will just wipe off all keys instead
of throwing the error. This is very confusing
and can lead to a lot of time wasted because
there's no indication that the JSON is incorrect.

Fixing this.

```release-note
NONE
```
* Sanitize RemoteEmail user prop

If the server is configured to hide user emails, the "RemoteEmail"
user property will be sanitized as well, effectively hiding the real
email of remote users.

* fix merge conflict

---------

Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
Co-authored-by: Mattermost Build <build@mattermost.com>
agarciamontoro and others added 29 commits May 5, 2025 13:07
Co-authored-by: unified-ci-app[bot] <121569378+unified-ci-app[bot]@users.noreply.github.com>
mattermost#30932)

The (s SqlChannelStore) getSidebarCategoriesT gets called quite frequently.
- Team switch
- WS reconnect
- Category created
- Category updated
- Category deleted

Of these 1 and 2 are probably the most commonly called sources. Based on that,
the sidebarChannels table is not that well-optimized. Even though
the query time might be reasonable, without an index, it has to churn a lot of
DB CPU for a sequential scan.

We add a new index to optimize this.

CREATE INDEX idx_sidebarchannels_categoryid ON sidebarchannels(categoryid);

```
Before:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=40854.18..40854.19 rows=4 width=193) (actual time=251.635..251.646 rows=204 loops=1)
   Sort Key: sidebarcategories.sortorder, sidebarchannels.sortorder
   Sort Method: quicksort  Memory: 65kB
   Buffers: shared hit=1203 read=23668
   ->  Nested Loop  (cost=8.87..40854.14 rows=4 width=193) (actual time=251.345..251.455 rows=204 loops=1)
         Buffers: shared hit=1203 read=23668
         ->  Nested Loop  (cost=0.41..9.47 rows=1 width=54) (actual time=0.068..0.074 rows=1 loops=1)
               Buffers: shared hit=5
               ->  Seq Scan on teams  (cost=0.00..1.03 rows=1 width=27) (actual time=0.024..0.026 rows=1 loops=1)
                     Filter: (((id)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND (deleteat = 0))
                     Rows Removed by Filter: 1
                     Buffers: shared hit=1
               ->  Index Scan using teammembers_pkey on teammembers  (cost=0.41..8.43 rows=1 width=27) (actual time=0.039..0.043 rows=1 loops=1)
                     Index Cond: (((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND ((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text))
                     Filter: (deleteat = 0)
                     Buffers: shared hit=4
         ->  Hash Right Join  (cost=8.45..40844.62 rows=4 width=193) (actual time=251.274..251.361 rows=204 loops=1)
               Hash Cond: ((sidebarchannels.categoryid)::text = (sidebarcategories.id)::text)
               Buffers: shared hit=1198 read=23668
               ->  Seq Scan on sidebarchannels  (cost=0.00..37514.77 rows=1265277 width=100) (actual time=0.043..99.345 rows=1265444 loops=1)
                     Buffers: shared hit=1194 read=23668
               ->  Hash  (cost=8.44..8.44 rows=1 width=158) (actual time=0.047..0.047 rows=6 loops=1)
                     Buckets: 1024  Batches: 1  Memory Usage: 10kB
                     Buffers: shared hit=4
                     ->  Index Scan using idx_sidebarcategories_userid_teamid on sidebarcategories  (cost=0.42..8.44 rows=1 width=158) (actual time=0.029..0.037 rows=6 loops=1)
                           Index Cond: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
                           Buffers: shared hit=4
 Planning:
   Buffers: shared hit=9
 Planning Time: 1.215 ms
 Execution Time: 251.755 ms
(31 rows)

After:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=1544.53..1544.54 rows=4 width=192) (actual time=0.834..0.859 rows=204 loops=1)
   Sort Key: sidebarcategories.sortorder, sidebarchannels.sortorder
   Sort Method: quicksort  Memory: 65kB
   Buffers: shared hit=58
   ->  Nested Loop Left Join  (cost=8.53..1544.49 rows=4 width=192) (actual time=0.066..0.252 rows=204 loops=1)
         Buffers: shared hit=58
         ->  Nested Loop  (cost=0.83..17.93 rows=1 width=157) (actual time=0.042..0.098 rows=6 loops=1)
               Buffers: shared hit=34
               ->  Nested Loop  (cost=0.42..9.48 rows=1 width=157) (actual time=0.030..0.049 rows=6 loops=1)
                     Buffers: shared hit=10
                     ->  Index Scan using idx_sidebarcategories_userid_teamid on sidebarcategories  (cost=0.42..8.44 rows=1 width=157) (actual time=0.018..0.022 rows=6 loops=1)
                           Index Cond: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
                           Buffers: shared hit=4
                     ->  Seq Scan on teams  (cost=0.00..1.03 rows=1 width=27) (actual time=0.002..0.003 rows=1 loops=6)
                           Filter: (((id)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND (deleteat = 0))
                           Rows Removed by Filter: 1
                           Buffers: shared hit=6
               ->  Index Scan using teammembers_pkey on teammembers  (cost=0.41..8.43 rows=1 width=27) (actual time=0.007..0.007 rows=1 loops=6)
                     Index Cond: (((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND ((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text))
                     Filter: (deleteat = 0)
                     Buffers: shared hit=24
         ->  Bitmap Heap Scan on sidebarchannels  (cost=7.69..1522.35 rows=421 width=100) (actual time=0.012..0.017 rows=34 loops=6)
               Recheck Cond: ((categoryid)::text = (sidebarcategories.id)::text)
               Heap Blocks: exact=6
               Buffers: shared hit=24
               ->  Bitmap Index Scan on idx_sidebarchannels_categoryid  (cost=0.00..7.58 rows=421 width=0) (actual time=0.010..0.010 rows=34 loops=6)
                     Index Cond: ((categoryid)::text = (sidebarcategories.id)::text)
                     Buffers: shared hit=18
 Planning:
   Buffers: shared hit=18
 Planning Time: 0.543 ms
 Execution Time: 0.968 ms
(32 rows)
```

I have also looked at potentially re-ordering the JOINs to make
sidebarchannels and sidebarcategories JOIN earlier, but that didn't give
a major benefit.

Also looked at adding a compound index with (categoryid, sortorder) to improve
sorting performance, but that didn't give a major benefit from what the single
column index already gives.

The `completePopulatingCategoryChannelsT` query also partially benefits
from this. But the Postgres optimizer sometimes selects the index on categoryId
and sometimes on ChannelId, both giving equivalent performance. So there's no major
improvement there, but at the same time, no regression as well.

```
Original:
[bigdb] # EXPLAIN (ANALYZE, BUFFERS) SELECT Id FROM ChannelMembers LEFT JOIN Channels ON Channels.Id=ChannelMembers.ChannelId WHERE (ChannelMembers.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND Channels.Type IN ('D'
                                                                                                                                                                                                                ,'G') AND Channels.DeleteAt = 0 AND NOT EXISTS ( SELECT 1 FROM SidebarChannels JOIN SidebarCategories on SidebarChannels.CategoryId=SidebarCategories.Id WHERE (SidebarChannels.ChannelId = ChannelMembers.ChannelI
                                                                                                                                                                                                                                                                                                                                                                                d AND SidebarCategories.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND SidebarCategories.TeamId = '3ee5y5ok6jgxicrmqstdnghmfr') )) ORDER BY DisplayName ASC;
                                                                                            QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=5864.68..5865.84 rows=463 width=40) (actual time=9.008..9.022 rows=39 loops=1)
   Sort Key: channels.displayname
   Sort Method: quicksort  Memory: 27kB
   Buffers: shared hit=2112
   ->  Nested Loop Anti Join  (cost=1.96..5844.18 rows=463 width=40) (actual time=0.188..8.932 rows=39 loops=1)
         Buffers: shared hit=2112
         ->  Nested Loop  (cost=0.99..3476.66 rows=463 width=67) (actual time=0.159..7.952 rows=39 loops=1)
               Buffers: shared hit=1956
               ->  Index Only Scan using idx_channelmembers_user_id_channel_id_last_viewed_at on channelmembers  (cost=0.56..40.78 rows=470 width=27) (actual time=0.036..0.467 rows=437 loops=1)
                     Index Cond: (userid = 'tc3p1yqw67d8idcp3g98awexqe'::text)
                     Heap Fetches: 45
                     Buffers: shared hit=208
               ->  Memoize  (cost=0.43..7.69 rows=1 width=40) (actual time=0.016..0.016 rows=0 loops=437)
                     Cache Key: channelmembers.channelid
                     Cache Mode: logical
                     Hits: 0  Misses: 437  Evictions: 0  Overflows: 0  Memory Usage: 42kB
                     Buffers: shared hit=1748
                     ->  Index Scan using channels_pkey on channels  (cost=0.42..7.68 rows=1 width=40) (actual time=0.015..0.015 rows=0 loops=437)
                           Index Cond: ((id)::text = (channelmembers.channelid)::text)
                           Filter: ((type = ANY ('{D,G}'::channel_type[])) AND (deleteat = 0))
                           Rows Removed by Filter: 1
                           Buffers: shared hit=1748
         ->  Nested Loop  (cost=0.97..5.10 rows=1 width=27) (actual time=0.023..0.023 rows=0 loops=39)
               Buffers: shared hit=156
               ->  Index Only Scan using sidebarchannels_pkey on sidebarchannels  (cost=0.55..4.56 rows=1 width=92) (actual time=0.022..0.022 rows=0 loops=39)
                     Index Cond: (channelid = (channelmembers.channelid)::text)
                     Heap Fetches: 0
                     Buffers: shared hit=156
               ->  Index Scan using sidebarcategories_pkey on sidebarcategories  (cost=0.42..0.48 rows=1 width=65) (never executed)
                     Index Cond: ((id)::text = (sidebarchannels.categoryid)::text)
                     Filter: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
 Planning:
   Buffers: shared hit=48 dirtied=1
 Planning Time: 2.222 ms
 Execution Time: 9.142 ms
(35 rows)

New:
[bigdb] # EXPLAIN (ANALYZE, BUFFERS) SELECT Id FROM ChannelMembers LEFT JOIN Channels ON Channels.Id=ChannelMembers.ChannelId WHERE (ChannelMembers.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND Channels.Type IN ('D'
                                                                                                                                                                                                                ,'G') AND Channels.DeleteAt = 0 AND NOT EXISTS ( SELECT 1 FROM SidebarChannels JOIN SidebarCategories on SidebarChannels.CategoryId=SidebarCategories.Id WHERE (SidebarChannels.ChannelId = ChannelMembers.ChannelId AND SidebarCategories.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND SidebarCategories.TeamId = '3ee5y5ok6jgxicrmqstdnghmfr') )) ORDER BY DisplayName ASC;
                                                                                            QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=5059.95..5061.11 rows=463 width=40) (actual time=12.072..12.086 rows=39 loops=1)
   Sort Key: channels.displayname
   Sort Method: quicksort  Memory: 27kB
   Buffers: shared hit=1984
   ->  Nested Loop Anti Join  (cost=9.10..5039.45 rows=463 width=40) (actual time=0.751..12.009 rows=39 loops=1)
         Join Filter: ((sidebarchannels.channelid)::text = (channelmembers.channelid)::text)
         Rows Removed by Join Filter: 7839
         Buffers: shared hit=1984
         ->  Nested Loop  (cost=0.99..3476.66 rows=463 width=67) (actual time=0.161..7.579 rows=39 loops=1)
               Buffers: shared hit=1956
               ->  Index Only Scan using idx_channelmembers_user_id_channel_id_last_viewed_at on channelmembers  (cost=0.56..40.78 rows=470 width=27) (actual time=0.036..0.449 rows=437 loops=1)
                     Index Cond: (userid = 'tc3p1yqw67d8idcp3g98awexqe'::text)
                     Heap Fetches: 45
                     Buffers: shared hit=208
               ->  Memoize  (cost=0.43..7.69 rows=1 width=40) (actual time=0.016..0.016 rows=0 loops=437)
                     Cache Key: channelmembers.channelid
                     Cache Mode: logical
                     Hits: 0  Misses: 437  Evictions: 0  Overflows: 0  Memory Usage: 42kB
                     Buffers: shared hit=1748
                     ->  Index Scan using channels_pkey on channels  (cost=0.42..7.68 rows=1 width=40) (actual time=0.014..0.014 rows=0 loops=437)
                           Index Cond: ((id)::text = (channelmembers.channelid)::text)
                           Filter: ((type = ANY ('{D,G}'::channel_type[])) AND (deleteat = 0))
                           Rows Removed by Filter: 1
                           Buffers: shared hit=1748
         ->  Materialize  (cost=8.11..1535.03 rows=4 width=27) (actual time=0.003..0.046 rows=201 loops=39)
               Buffers: shared hit=28
               ->  Nested Loop  (cost=8.11..1535.01 rows=4 width=27) (actual time=0.099..0.383 rows=201 loops=1)
                     Buffers: shared hit=28
                     ->  Index Scan using idx_sidebarcategories_userid_teamid on sidebarcategories  (cost=0.42..8.44 rows=1 width=65) (actual time=0.047..0.057 rows=6 loops=1)
                           Index Cond: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
                           Buffers: shared hit=4
                     ->  Bitmap Heap Scan on sidebarchannels  (cost=7.69..1522.35 rows=421 width=92) (actual time=0.028..0.040 rows=34 loops=6)
                           Recheck Cond: ((categoryid)::text = (sidebarcategories.id)::text)
                           Heap Blocks: exact=6
                           Buffers: shared hit=24
                           ->  Bitmap Index Scan on idx_sidebarchannels_categoryid  (cost=0.00..7.58 rows=421 width=0) (actual time=0.023..0.023 rows=34 loops=6)
                                 Index Cond: ((categoryid)::text = (sidebarcategories.id)::text)
                                 Buffers: shared hit=18
 Planning:
   Buffers: shared hit=51
 Planning Time: 2.240 ms
 Execution Time: 12.210 ms
(42 rows)
```

Analysis on MySQL for completion:
```
Before:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Sort: SidebarCategories.SortOrder, SidebarChannels.SortOrder  (actual time=277.675..277.675 rows=4 loops=1)
    -> Stream results  (cost=138558.36 rows=1287808) (actual time=242.506..277.650 rows=4 loops=1)
        -> Left hash join (<hash>(SidebarChannels.CategoryId)=<hash>(SidebarCategories.Id)), extra conditions: (SidebarChannels.CategoryId = SidebarCategories.Id)  (cost=138558.36 rows=1287808) (actual time=242.498..277.626 rows=4 loops=1)
            -> Index lookup on SidebarCategories using idx_sidebarcategories_userid_teamid (UserId='qdggj9pyobgkjpj8htwzizks1r', TeamId='xmh7bupzajnudqf3h4mm76qapy')  (cost=1.40 rows=4) (actual time=0.092..0.094 rows=4 loops=1)
            -> Hash
                -> Table scan on SidebarChannels  (cost=8394.55 rows=321952) (actual time=0.123..106.334 rows=300002 loops=1)
 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

After:
----------------------------------------------------------------+
| -> Sort: SidebarCategories.SortOrder, SidebarChannels.SortOrder  (actual time=0.739..0.742 rows=4 loops=1)
    -> Stream results  (cost=6.80 rows=7) (actual time=0.468..0.703 rows=4 loops=1)
        -> Nested loop left join  (cost=6.80 rows=7) (actual time=0.456..0.673 rows=4 loops=1)
            -> Index lookup on SidebarCategories using idx_sidebarcategories_userid_teamid (UserId='qdggj9pyobgkjpj8htwzizks1r', TeamId='xmh7bupzajnudqf3h4mm76qapy')  (cost=4.38 rows=4) (actual time=0.302..0.313 rows=4 loops=1)
            -> Index lookup on SidebarChannels using idx_sidebarchannels_categoryid (CategoryId=SidebarCategories.Id)  (cost=0.48 rows=2) (actual time=0.085..0.087 rows=0 loops=4)
 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```

Timing wise, it takes around 2s to add the index on a table with 1.2M rows
for Postgres. And it takes around 5s on MySQL on a table with 300K rows.
It looks like it takes longer on MySQL, but since both migrations are
non-locking, it should be fine.

https://mattermost.atlassian.net/browse/MM-63756
```release-note
NONE
```
…termost#30963) (mattermost#30967)

For our MySQL customers, we have discovered that the query is not
able to choose the right plan by itself without adequate hints.

This is only for MySQL as we have confirmed from multiple customers
that Postgres takes the right index idx_sidebarcategories_userid_teamid
for the sidebarCategories table. And if it doesn't, then a VACUUM ANALYZE
fixes it.

But for MySQL, we have to do two things:
- Pass an index hint to let it use idx_sidebarcategories_userid_teamid.
- Pass an optimizer hint to materialize the sub-query. This is used
to materialize the doesNotHaveSidebarChannel sub-query into a temporary
table, letting MySQL reuse the contents of the table for further processing
in the parent sections of the query.

I have confirmed both locally and in the customer environment
that it gives a clear benefit.

*LOCAL*

OLD:
```
| -> Nested loop antijoin  (cost=2889.85 rows=19767) (actual time=3.355..38.033 rows=15 loops=1)
    -> Nested loop inner join  (cost=66.65 rows=110) (actual time=0.410..1.689 rows=220 loops=1)
        -> Filter: ((Channels.DeleteAt = 0) and (Channels.`Type` in ('O','P')))  (cost=25.25 rows=110) (actual time=0.394..0.886 rows=220 loops=1)
            -> Index lookup on Channels using idx_channels_team_id_display_name (TeamId='team01'), with index condition: (Channels.Id is not null)  (cost=25.25 rows=220) (actual time=0.389..0.793 rows=220 loops=1)
        -> Single-row covering index lookup on ChannelMembers using PRIMARY (ChannelId=Channels.Id, UserId='user000')  (cost=0.28 rows=1) (actual time=0.003..0.003 rows=1 loops=220)
    -> Nested loop inner join  (cost=4967.50 rows=180) (actual time=0.165..0.165 rows=1 loops=220)
        -> Covering index lookup on SidebarChannels using PRIMARY (ChannelId=Channels.Id)  (cost=7.86 rows=180) (actual time=0.055..0.062 rows=13 loops=220)
        -> Filter: ((SidebarCategories.TeamId = 'team01') and (SidebarCategories.UserId = 'user000'))  (cost=44.93 rows=1) (actual time=0.008..0.008 rows=0 loops=2881)
            -> Single-row index lookup on SidebarCategories using PRIMARY (Id=SidebarChannels.CategoryId)  (cost=44.93 rows=1) (actual time=0.006..0.006 rows=1 loops=2881)
 |
```

NEW:
```
 | -> Nested loop antijoin  (cost=5879.73 rows=58021) (actual time=1.544..3.135 rows=15 loops=1)
    -> Nested loop inner join  (cost=66.65 rows=110) (actual time=0.421..1.778 rows=220 loops=1)
        -> Filter: ((Channels.DeleteAt = 0) and (Channels.`Type` in ('O','P')))  (cost=25.25 rows=110) (actual time=0.405..0.945 rows=220 loops=1)
            -> Index lookup on Channels using idx_channels_team_id_display_name (TeamId='team01'), with index condition: (Channels.Id is not null)  (cost=25.25 rows=220) (actual time=0.400..0.859 rows=220 loops=1)
        -> Single-row covering index lookup on ChannelMembers using PRIMARY (ChannelId=Channels.Id, UserId='user000')  (cost=0.28 rows=1) (actual time=0.003..0.004 rows=1 loops=220)
    -> Single-row index lookup on <subquery2> using <auto_distinct_key> (ChannelId=Channels.Id)  (cost=130.37..130.37 rows=1) (actual time=0.006..0.006 rows=1 loops=220)
        -> Materialize with deduplication  (cost=130.35..130.35 rows=527) (actual time=1.118..1.118 rows=205 loops=1)
            -> Filter: (SidebarChannels.ChannelId is not null)  (cost=77.61 rows=527) (actual time=0.059..0.851 rows=523 loops=1)
                -> Nested loop inner join  (cost=77.61 rows=527) (actual time=0.058..0.786 rows=523 loops=1)
                    -> Covering index lookup on SidebarCategories using idx_sidebarcategories_userid_teamid (UserId='user000', TeamId='team01')  (cost=2.81 rows=15) (actual time=0.025..0.031 rows=15 loops=1)
                    -> Covering index lookup on SidebarChannels using idx_sidebarchannels_categoryid (CategoryId=SidebarCategories.Id)  (cost=1.70 rows=35) (actual time=0.032..0.046 rows=35 loops=15)
```

Performance improvement from 38ms to 3ms.

*CUSTOMER ENV* (with sensitive data wiped off)

OLD:
```
| -> Sort: channels.DisplayName  (actual time=512..512 rows=5 loops=1)
    -> Stream results  (cost=3.28 rows=1.44) (actual time=223..512 rows=5 loops=1)
        -> Nested loop antijoin  (cost=3.28 rows=1.44) (actual time=223..512 rows=5 loops=1)
            -> Nested loop inner join  (cost=3.02 rows=0.3) (actual time=0.025..0.0878 rows=5 loops=1)
                -> Covering index lookup on ChannelMembers using idx_channelmembers_user_id_channel_id_last_viewed_at (UserId='')  (cost=0.916 rows=6) (actual time=0.0146..0.023 rows=6 loops=1)
                -> Filter: ((channels.DeleteAt = 0) and (channels.TeamId = '') and (channels.`Type` in ('O','P')))  (cost=0.251 rows=0.05) (actual time=0.00999..0.0102 rows=0.833 loops=6)
                    -> Single-row index lookup on Channels using PRIMARY (Id=channelmembers.ChannelId)  (cost=0.251 rows=1) (actual time=0.00778..0.00785 rows=1 loops=6)
            -> Nested loop inner join  (cost=2.85 rows=4.81) (actual time=102..102 rows=0 loops=5)
                -> Covering index lookup on SidebarChannels using PRIMARY (ChannelId=channelmembers.ChannelId)  (cost=2.01 rows=4.81) (actual time=0.0125..13.8 rows=24134 loops=5)
                -> Filter: ((sidebarcategories.TeamId = '') and (sidebarcategories.UserId = ''))  (cost=1.54 rows=1) (actual time=0.00359..0.00359 rows=0 loops=120671)
                    -> Single-row index lookup on SidebarCategories using PRIMARY (Id=sidebarchannels.CategoryId)  (cost=1.54 rows=1) (actual time=0.00316..0.00319 rows=1 loops=120671)
```

NEW:
```
Here is the output

| -> Sort: channels.DisplayName  (actual time=0.12..0.12 rows=5 loops=1)
    -> Stream results  (cost=3.45 rows=4.01) (actual time=0.0797..0.11 rows=5 loops=1)
        -> Nested loop antijoin  (cost=3.45 rows=4.01) (actual time=0.0769..0.106 rows=5 loops=1)
            -> Nested loop inner join  (cost=3.02 rows=0.3) (actual time=0.0291..0.0555 rows=5 loops=1)
                -> Covering index lookup on ChannelMembers using idx_channelmembers_user_id_channel_id_last_viewed_at (UserId='')  (cost=0.916 rows=6) (actual time=0.0145..0.0162 rows=6 loops=1)
                -> Filter: ((channels.DeleteAt = 0) and (channels.TeamId = '') and (channels.`Type` in ('O','P')))  (cost=0.251 rows=0.05) (actual time=0.00611..0.00619 rows=0.833 loops=6)
                    -> Single-row index lookup on Channels using PRIMARY (Id=channelmembers.ChannelId)  (cost=0.251 rows=1) (actual time=0.0053..0.00534 rows=1 loops=6)
            -> Single-row index lookup on <subquery2> using <auto_distinct_key> (ChannelId=channelmembers.ChannelId)  (cost=7.01..7.01 rows=1) (actual time=0.00956..0.00956 rows=0 loops=5)
                -> Materialize with deduplication  (cost=7..7 rows=13.4) (actual time=0.0451..0.0451 rows=0 loops=1)
                    -> Filter: (sidebarchannels.ChannelId is not null)  (cost=5.66 rows=13.4) (actual time=0.0441..0.0441 rows=0 loops=1)
                        -> Nested loop inner join  (cost=5.66 rows=13.4) (actual time=0.0439..0.0439 rows=0 loops=1)
                            -> Covering index lookup on SidebarCategories using idx_sidebarcategories_userid_teamid (UserId='', TeamId='')  (cost=0.592 rows=3) (actual time=0.0105..0.0134 rows=3 loops=1)
                            -> Covering index lookup on SidebarChannels using idx_sidebarchannels_categoryid (CategoryId=sidebarcategories.Id)  (cost=1.39 rows=4.46) (actual time=0.00999..0.00999 rows=0 loops=3)
```

Performance improvement from 512ms to 0.12ms.

https://mattermost.atlassian.net/browse/MM-64209

```release-note
NONE
```

(cherry picked from commit 0ebd3e8)

Co-authored-by: Agniva De Sarker <agnivade@yahoo.co.in>
Co-authored-by: unified-ci-app[bot] <121569378+unified-ci-app[bot]@users.noreply.github.com>
…ermost#30628) (mattermost#30987)

(cherry picked from commit 7250095)

Co-authored-by: Claudio Costa <cstcld91@gmail.com>
* MM-64336: simplify doc extractor

Avoid creating a whole temporary directory when a single temporary file suffices.

Fixes: https://mattermost.atlassian.net/browse/MM-64337

* clarify -* semantics

(cherry picked from commit 65aec10)

Co-authored-by: Jesse Hallam <jesse.hallam@gmail.com>
Co-authored-by: unified-ci-app[bot] <121569378+unified-ci-app[bot]@users.noreply.github.com>
…) (mattermost#31273)

* Improve validation of imported attachments

* Simplify multiple errors handling

* Improve logic

* Fix abs paths in tests

* Remove redundant clean

* Implement additional validation

* Fix absolute paths in test

* Add additional tests

---------

Co-authored-by: Lorenzo Gallegos <1328683+enzowritescode@users.noreply.github.com>
Co-authored-by: unified-ci-app[bot] <121569378+unified-ci-app[bot]@users.noreply.github.com>
…most#31659) (mattermost#31793)

(cherry picked from commit c5f79bb)

Co-authored-by: catalintomai <56169943+catalintomai@users.noreply.github.com>
(cherry picked from commit d8758f8)

Co-authored-by: Miguel de la Cruz <miguel@mcrx.me>
Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
(cherry picked from commit a8fa77f)

Co-authored-by: catalintomai <56169943+catalintomai@users.noreply.github.com>
…st#33370) (mattermost#33392)

* MM-64658 Fix handling of upload sessions

* Fix style issue

(cherry picked from commit d6b35c4)

Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
Co-authored-by: Daniel Espino García <larkox@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
…rmost#33376) (mattermost#33471)

The actual work needed for this ticket is already done.
Fixing some auxiliary things.

https://mattermost.atlassian.net/browse/MM-64675

```release-note
NONE
```

(cherry picked from commit d3f3129)

Co-authored-by: Agniva De Sarker <agnivade@yahoo.co.in>
* Add URL validation to LinkMetadata cache and store (mattermost#31814)

* test hash collisions in link metadata

* guard against hash collisions in link metadata

(cherry picked from commit 1496d1a)

* rm unsupported mainHelper.Parallel in this branch

---------

Co-authored-by: Jesse Hallam <jesse.hallam@gmail.com>
Co-authored-by: Jesse Hallam <jesse@mattermost.com>
@flrnull flrnull merged commit 88b8d87 into platrum:master Aug 4, 2025
2 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.