Skip to content

Commit 7047cd0

Browse files
jolavilletteclaude
andcommitted
gxs: bulk read-status for channels and boards (extend mark-all-as-read 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>
1 parent 6a39b90 commit 7047cd0

6 files changed

Lines changed: 119 additions & 0 deletions

File tree

src/retroshare/rsgxschannels.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,22 @@ class RsGxsChannels: public RsGxsIfaceHelper, public RsGxsCommentService
430430
*/
431431
virtual bool setMessageReadStatus(const RsGxsGrpMsgIdPair &msgId, bool read) =0;
432432

433+
/**
434+
* @brief Mark several messages of a channel read/unread in one batch. Blocking.
435+
*
436+
* Like setMessageReadStatus() but queues all the status changes at once: they
437+
* are persisted in a single database transaction and only one event is
438+
* emitted, so it stays cheap even for thousands of posts and is meant to be
439+
* called from a background thread so the GUI never blocks.
440+
* @param[in] channelId channel group identifier
441+
* @param[in] msgIds identifiers of the posts to update
442+
* @param[in] read true to mark as read, false to mark as unread
443+
* @return false on error, true otherwise
444+
*/
445+
virtual bool setMessageReadStatus( const RsGxsGroupId& channelId,
446+
const std::vector<RsGxsMessageId>& msgIds,
447+
bool read ) =0;
448+
433449
/**
434450
* @brief Share channel publishing key
435451
* This can be used to authorize other peers to post on the channel

src/retroshare/rsposted.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,22 @@ class RsPosted : public RsGxsIfaceHelper, public RsGxsCommentService
402402
*/
403403
virtual bool setPostReadStatus(const RsGxsGrpMsgIdPair& msgId, bool read) = 0;
404404

405+
/**
406+
* @brief Mark several posts of a board read/unread in one batch. Blocking.
407+
*
408+
* Like setPostReadStatus() but queues all the status changes at once: they
409+
* are persisted in a single database transaction and only one event is
410+
* emitted, so it stays cheap even for thousands of posts and is meant to be
411+
* called from a background thread so the GUI never blocks.
412+
* @param[in] boardId board group identifier
413+
* @param[in] msgIds identifiers of the posts to update
414+
* @param[in] read true to mark as read, false to mark as unread
415+
* @return false on error, true otherwise
416+
*/
417+
virtual bool setPostReadStatus( const RsGxsGroupId& boardId,
418+
const std::vector<RsGxsMessageId>& msgIds,
419+
bool read ) = 0;
420+
405421
enum RS_DEPRECATED RankType {TopRankType, HotRankType, NewRankType };
406422

407423
RS_DEPRECATED_FOR(getBoardsInfo)

src/services/p3gxschannels.cc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,6 +2041,46 @@ bool p3GxsChannels::setMessageReadStatus(const RsGxsGrpMsgIdPair &msgId, bool re
20412041
return true;
20422042
}
20432043

2044+
bool p3GxsChannels::setMessageReadStatus(const RsGxsGroupId& channelId, const std::vector<RsGxsMessageId>& msgIds, bool read)
2045+
{
2046+
if(msgIds.empty())
2047+
return true;
2048+
2049+
uint32_t mask = GXS_SERV::GXS_MSG_STATUS_GUI_NEW | GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD;
2050+
uint32_t status = read ? 0 : GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD;
2051+
2052+
// Queue every status change at once. They are all drained together by a
2053+
// single processMsgMetaChanges() tick (one DB transaction), instead of one
2054+
// blocking request + one detached thread + one event per message.
2055+
std::vector<uint32_t> tokens;
2056+
tokens.reserve(msgIds.size());
2057+
2058+
for(const RsGxsMessageId& msgId : msgIds)
2059+
{
2060+
uint32_t token;
2061+
setMsgStatusFlags(token, RsGxsGrpMsgIdPair(channelId, msgId), status, mask);
2062+
tokens.push_back(token);
2063+
}
2064+
2065+
// All tokens complete in the same tick, so waiting on the last is enough.
2066+
waitToken(tokens.back(), std::chrono::milliseconds(30000));
2067+
2068+
RsGxsGrpMsgIdPair p;
2069+
for(uint32_t token : tokens)
2070+
acknowledgeMsg(token, p);
2071+
2072+
// One single event for the whole batch (consumers only need the group id).
2073+
if(rsEvents)
2074+
{
2075+
auto ev = std::make_shared<RsGxsChannelEvent>();
2076+
ev->mChannelGroupId = channelId;
2077+
ev->mChannelEventCode = RsChannelEventCode::READ_STATUS_CHANGED;
2078+
rsEvents->postEvent(ev);
2079+
}
2080+
2081+
return true;
2082+
}
2083+
20442084
bool p3GxsChannels::shareChannelKeys(
20452085
const RsGxsGroupId& channelId, const std::set<RsPeerId>& peers)
20462086
{

src/services/p3gxschannels.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ class p3GxsChannels: public RsGenExchange, public RsGxsChannels,
106106
/// @see RsGxsChannels
107107
bool setMessageReadStatus(const RsGxsGrpMsgIdPair& msgId, bool read) override;
108108

109+
/// @see RsGxsChannels (batch variant)
110+
bool setMessageReadStatus( const RsGxsGroupId& channelId,
111+
const std::vector<RsGxsMessageId>& msgIds,
112+
bool read ) override;
113+
109114
virtual bool groupShareKeys(const RsGxsGroupId &groupId, const std::set<RsPeerId>& peers) override;
110115

111116
// no tokens... should be cached.

src/services/p3posted.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,45 @@ bool p3Posted::setPostReadStatus(const RsGxsGrpMsgIdPair &msgId, bool read)
707707
{
708708
return setCommentReadStatus(msgId,read);
709709
}
710+
bool p3Posted::setPostReadStatus(const RsGxsGroupId& boardId, const std::vector<RsGxsMessageId>& msgIds, bool read)
711+
{
712+
if(msgIds.empty())
713+
return true;
714+
715+
uint32_t mask = GXS_SERV::GXS_MSG_STATUS_GUI_NEW | GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD;
716+
uint32_t status = read ? 0 : GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD;
717+
718+
// Queue every status change at once. They are all drained together by a
719+
// single processMsgMetaChanges() tick (one DB transaction), instead of one
720+
// blocking request + one detached thread + one event per message.
721+
std::vector<uint32_t> tokens;
722+
tokens.reserve(msgIds.size());
723+
724+
for(const RsGxsMessageId& msgId : msgIds)
725+
{
726+
uint32_t token;
727+
setMsgStatusFlags(token, RsGxsGrpMsgIdPair(boardId, msgId), status, mask);
728+
tokens.push_back(token);
729+
}
730+
731+
// All tokens complete in the same tick, so waiting on the last is enough.
732+
waitToken(tokens.back(), std::chrono::milliseconds(30000));
733+
734+
RsGxsGrpMsgIdPair p;
735+
for(uint32_t token : tokens)
736+
acknowledgeMsg(token, p);
737+
738+
// One single event for the whole batch (consumers only need the group id).
739+
if(rsEvents)
740+
{
741+
auto ev = std::make_shared<RsGxsPostedEvent>();
742+
ev->mPostedGroupId = boardId;
743+
ev->mPostedEventCode = RsPostedEventCode::READ_STATUS_CHANGED;
744+
rsEvents->postEvent(ev);
745+
}
746+
747+
return true;
748+
}
710749
bool p3Posted::setCommentReadStatus(const RsGxsGrpMsgIdPair &msgId, bool read)
711750
{
712751
uint32_t token;

src/services/p3posted.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ virtual void receiveHelperChanges(std::vector<RsGxsNotify*>& changes)
125125

126126
bool setCommentReadStatus(const RsGxsGrpMsgIdPair &msgId, bool read) override;
127127
bool setPostReadStatus(const RsGxsGrpMsgIdPair &msgId, bool read) override;
128+
bool setPostReadStatus( const RsGxsGroupId& boardId,
129+
const std::vector<RsGxsMessageId>& msgIds,
130+
bool read ) override;
128131

129132
bool getRelatedComments( const RsGxsGroupId& gid,const std::set<RsGxsMessageId>& msgIds, std::vector<RsGxsComment> &comments ) override;
130133

0 commit comments

Comments
 (0)