Fix UI freeze on "mark all as read/unread" for forums, channels and boards#331
Open
jolavillette wants to merge 2 commits into
Open
Fix UI freeze on "mark all as read/unread" for forums, channels and boards#331jolavillette wants to merge 2 commits into
jolavillette wants to merge 2 commits into
Conversation
jolavillette
force-pushed
the
fix/gxs-mark-all-read-nofreeze
branch
from
July 18, 2026 13:33
20e3bdc to
a655d29
Compare
…s-read hang) Marking a large forum (thousands of posts) "read" used to be catastrophic: the GUI issued one blocking markRead() per post, and the GXS backend wrote each status change to the SQLCipher DB in its own implicit transaction (one fsync per message). On an 8000-post forum this took over an hour and, if force-quit, left most posts still unread. Backend changes: - RsGeneralDataService: add a batch updateMessageMetaData(vector) overload. The default loops; RsDataService overrides it to persist the whole batch in a single transaction, held under one mDbMutex so nothing interleaves. - RsGenExchange::processMsgMetaChanges(): resolve all status masks first, then persist every queued change through that single batched transaction. - RsGxsForums / p3GxsForums: add a bulk markRead(forumId, msgIds, read) that queues all status changes at once and emits a single event, instead of one blocking request + one event per message. "Mark all as read" now persists in a single transaction (one fsync) whatever the number of posts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d fix) Same treatment as the forum bulk markRead(), now for channels and boards, so their "mark all as read/unread" also persists in a single transaction and emits a single event instead of one blocking request + one event per post: - RsGxsChannels / p3GxsChannels: add setMessageReadStatus(channelId, msgIds, read). - RsPosted / p3Posted: add setPostReadStatus(boardId, msgIds, read). Both reuse the batched, single-transaction processMsgMetaChanges() path added for forums, which already benefits every GXS service. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jolavillette
force-pushed
the
fix/gxs-mark-all-read-nofreeze
branch
from
July 18, 2026 19:01
a655d29 to
7047cd0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
works with retroshare-gui pr/3274
Fix UI freeze on "mark all as read/unread" for forums, channels and boards
Problem
Marking a large GXS group read — right-click → Mark all as read (or unread) — froze the UI for a very long time and could appear to hang indefinitely. On an 8000-post forum the hourglass stayed up for over an hour; force-quitting mid-way left thousands of posts still unread.
Root cause
Two independent amplifiers, both triggered per message:
std::threadper changed post (each blocking up to 5s waiting for its token to complete) and emitted onedataChanged()per post. Marking N posts created ~N threads and ~N signals, all driven from the GUI thread.RsGenExchange::processMsgMetaChanges()wrote each status change to the GXS database in its own implicit transaction (one fsync per message). On the SQLCipher-encrypted store this meant thousands of serial encrypted commits.Fix
Backend (
libretroshare)RsGeneralDataService: new batchupdateMessageMetaData(std::vector<MsgLocMetaData>)overload (default loops over the single version).RsDataServiceoverrides it to persist the whole batch in a single transaction, held under one DB mutex so nothing interleaves.RsGenExchange::processMsgMetaChanges(): resolve all status masks first, then persist every queued change through that single transaction. This benefits every GXS service.RsGxsForums::markRead(forumId, msgIds, read)RsGxsChannels::setMessageReadStatus(channelId, msgIds, read)RsPosted::setPostReadStatus(boardId, msgIds, read)GUI (
retroshare-gui)GxsForumModel,GxsChannelPostsModelandPostedPostsModel: "mark all as read/unread" now collects the affected message ids, updates the in-memory model, issues one background batch call, and refreshes the view once — instead of one detached thread + one event + onedataChanged()per post.Result
The GUI thread now does
O(n)in-memory work plus one thread and one signal, regardless of how many posts are affected, so it stays responsive on arbitrarily large groups. Persistence happens in a single transaction (one fsync). Works symmetrically for read and unread, on forums, channels and boards.Notes
markRead/setMessageReadStatus/setPostReadStatusare unchanged; the batch variants are additive.retroshare-gui⇄libretroshare): the GUI batch calls require the new backend overloads. Companion PR:Testing
Open a forum/channel/board with thousands of posts, then right-click → Mark all as read, and again → Mark all as unread: