UnigramDev/Unigram/develop • 8fd02b8 • 4 files, +248/-83 Guard the ForumTopicService collections, an

Telegram github commits and releases

Telegram github commits and releases

@tgappsupdates

Broadcast from the most important Telegram clients' repositories

4,538 subscribers
Open in Telegram
UnigramDev/Unigram/develop8fd02b84 files, +248/-83
Guard the ForumTopicService collections, and finish Clear()

Two findings from the same review, landing together because the review doc
records both and the commit hook commits whole files, so splitting them would
mean checking one item off before its fix existed.

ForumTopicService kept six of its eight collections in plain Dictionary, List
and HashSet: _topics, _messages, _pinnedTopicIds, _deletedTopicIds,
_pendingNewTopics and _pendingLastReadInboxMessageId. Every Update* method
writes them from the TDLib thread while GetTopic and GetTopics read them from
the UI thread — and GetTopic writes too, since recording a pending request is
what stops a miss from sending one getForumTopic per enumeration. Only _order
and _unreadTopicIds were guarded. A concurrent mutation of a Dictionary does not
throw, it spins.

All eight now sit behind one private lock, absorbing the two existing lock
objects so there is a single domain and no ordering between them to get wrong.
A ReaderWriterDictionary would have matched DirectMessagesChatTopicService, but
it covers only the two Dictionary fields; the List, the SortedSet and the three
HashSets would still need a lock, leaving two domains and real compounds
spanning both — UpdatePinnedTopics reads _pinnedTopicIds then _topics, Order
reads _deletedTopicIds and _pinnedTopicIds, the batch load touches four at once.
One lock makes those atomic and a lock cycle impossible. The dictionary reads go
through TryGetTopic/TryGetTopicByMessage so the backing store stays cheap to
change if that is revisited.

Critical sections stay small and publishes stay outside them, which shrinks the
separate finding about publishing under the lock rather than growing it:
SetPinnedForumTopics and UpdatePinnedTopics now collect under the lock and
reorder outside it, leaving only the batch load still publishing while held. The
ForumTopic objects themselves are still handed to the UI and mutated by the
update methods unsynchronised, exactly as ClientService does with Chat and User;
this fixes container corruption, which is the part that spins forever.

Clear() was missing eight caches. _activeStories was the one that bit: the story
ordering was cleared but the stories were not, so after logout GetActiveStories
still served the previous account's state. The three download sets moved into a
ClearDownloads helper next to their declarations, since they need _downloadsLock
and the reason they must not outlive an authorization belongs where they are
declared — file ids only mean anything within one session, and those sets are
also the only state here that grows for the life of the process.

Checked by enumerating every private field across the seven partials and diffing
against what Clear() touches, rather than by re-reading it: what it now leaves
alone is the injected dependencies and the lock objects, and nothing else.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop330db012 files, +17/-5
Fix monospace font lookup

UnigramDev/Unigram/develop26179e52 files, +12/-6
Resolve only the unknown sources on the second pass

When any ssrc could not be matched, the retry walked the whole request again and
re-added every source the first pass had already resolved. It stayed harmless
only because tgcalls asks for one ssrc at a time, which is exactly the assumption
the comment above it leans on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
Open post in Telegram