Skip to content

Commit 0bb489f

Browse files
committed
fix_: cache read-only communities to reduce memory pressure
Full database reads, especially on message receipt, caused repeated allocations and high RAM usage due to unmarshaling full community objects. This change introduces a lightweight cache (up to 5 entries, 1-minute TTL) to avoid redundant DB access and deserialization for commonly used communities.
1 parent 6dcaa8e commit 0bb489f

File tree

4 files changed

+52
-22
lines changed

4 files changed

+52
-22
lines changed

protocol/communities/community.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ type Community struct {
7373
mediaServer server.MediaServerInterface
7474
}
7575

76+
type ReadonlyCommunity interface {
77+
ID() types.HexBytes
78+
IsControlNode() bool
79+
CanPost(pk *ecdsa.PublicKey, chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error)
80+
IsBanned(pk *ecdsa.PublicKey) bool
81+
}
82+
7683
func New(config Config, timesource common.TimeSource, encryptor DescriptionEncryptor, mediaServer server.MediaServerInterface) (*Community, error) {
7784
if config.MemberIdentity == nil {
7885
return nil, errors.New("no member identity")

protocol/communities/manager.go

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"time"
1717

1818
"github.com/golang/protobuf/proto"
19+
"github.com/jellydator/ttlcache/v3"
1920

2021
"github.com/google/uuid"
2122
"github.com/pkg/errors"
@@ -113,6 +114,7 @@ type Manager struct {
113114
communityLock *CommunityLock
114115
mediaServer server.MediaServerInterface
115116
communityImageVersions map[string]uint32
117+
cache *ttlcache.Cache[string, ReadonlyCommunity]
116118
}
117119

118120
type CommunityLock struct {
@@ -432,6 +434,7 @@ func NewManager(
432434
communityLock: NewCommunityLock(logger),
433435
mediaServer: mediaServer,
434436
communityImageVersions: make(map[string]uint32),
437+
cache: ttlcache.New(ttlcache.WithCapacity[string, ReadonlyCommunity](5), ttlcache.WithTTL[string, ReadonlyCommunity](time.Minute)),
435438
}
436439

437440
manager.persistence = &Persistence{
@@ -919,7 +922,7 @@ func (m *Manager) CreateCommunity(request *requests.CreateCommunity, publish boo
919922
// We join any community we create
920923
community.Join()
921924

922-
err = m.persistence.SaveCommunity(community)
925+
err = m.SaveCommunity(community)
923926
if err != nil {
924927
return nil, err
925928
}
@@ -1727,7 +1730,7 @@ func (m *Manager) RemovePrivateKey(id types.HexBytes) (*Community, error) {
17271730
}
17281731

17291732
community.config.PrivateKey = nil
1730-
err = m.persistence.SaveCommunity(community)
1733+
err = m.SaveCommunity(community)
17311734
if err != nil {
17321735
return community, err
17331736
}
@@ -1804,7 +1807,7 @@ func (m *Manager) ImportCommunity(key *ecdsa.PrivateKey, clock uint64) (*Communi
18041807
}
18051808

18061809
community.Join()
1807-
err = m.persistence.SaveCommunity(community)
1810+
err = m.SaveCommunity(community)
18081811
if err != nil {
18091812
return nil, err
18101813
}
@@ -2038,7 +2041,7 @@ func (m *Manager) EditChatFirstMessageTimestamp(communityID types.HexBytes, chat
20382041
return nil, nil, err
20392042
}
20402043

2041-
err = m.persistence.SaveCommunity(community)
2044+
err = m.SaveCommunity(community)
20422045
if err != nil {
20432046
return nil, nil, err
20442047
}
@@ -2401,7 +2404,7 @@ func (m *Manager) handleCommunityDescriptionMessageCommon(community *Community,
24012404
changes.ShouldMemberJoin = true
24022405
}
24032406

2404-
err = m.persistence.SaveCommunity(community)
2407+
err = m.SaveCommunity(community)
24052408
if err != nil {
24062409
return nil, err
24072410
}
@@ -2488,7 +2491,7 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message
24882491
}
24892492
}
24902493

2491-
err = m.persistence.SaveCommunity(community)
2494+
err = m.SaveCommunity(community)
24922495
if err != nil {
24932496
return nil, err
24942497
}
@@ -2500,7 +2503,7 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message
25002503

25012504
m.publish(&Subscription{Community: community})
25022505
} else {
2503-
err = m.persistence.SaveCommunity(community)
2506+
err = m.SaveCommunity(community)
25042507
if err != nil {
25052508
return nil, err
25062509
}
@@ -3246,7 +3249,7 @@ func (m *Manager) HandleCommunityEditSharedAddresses(signer *ecdsa.PublicKey, re
32463249
return err
32473250
}
32483251

3249-
err = m.persistence.SaveCommunity(community)
3252+
err = m.SaveCommunity(community)
32503253
if err != nil {
32513254
return err
32523255
}
@@ -3651,7 +3654,7 @@ func (m *Manager) JoinCommunity(id types.HexBytes, forceJoin bool) (*Community,
36513654
return community, ErrOrgAlreadyJoined
36523655
}
36533656
community.Join()
3654-
err = m.persistence.SaveCommunity(community)
3657+
err = m.SaveCommunity(community)
36553658
if err != nil {
36563659
return nil, err
36573660
}
@@ -3667,7 +3670,7 @@ func (m *Manager) SpectateCommunity(id types.HexBytes) (*Community, error) {
36673670
return nil, err
36683671
}
36693672
community.Spectate()
3670-
if err = m.persistence.SaveCommunity(community); err != nil {
3673+
if err = m.SaveCommunity(community); err != nil {
36713674
return nil, err
36723675
}
36733676
return community, nil
@@ -3707,7 +3710,7 @@ func (m *Manager) UpdateCommunityDescriptionMagnetlinkMessageClock(communityID t
37073710
return err
37083711
}
37093712
community.config.CommunityDescription.ArchiveMagnetlinkClock = clock
3710-
return m.persistence.SaveCommunity(community)
3713+
return m.SaveCommunity(community)
37113714
}
37123715

37133716
func (m *Manager) UpdateMagnetlinkMessageClock(communityID types.HexBytes, clock uint64) error {
@@ -3734,7 +3737,7 @@ func (m *Manager) LeaveCommunity(id types.HexBytes) (*Community, error) {
37343737
community.RemoveOurselvesFromOrg(&m.identity.PublicKey)
37353738
community.Leave()
37363739

3737-
if err = m.persistence.SaveCommunity(community); err != nil {
3740+
if err = m.SaveCommunity(community); err != nil {
37383741
return nil, err
37393742
}
37403743

@@ -3757,7 +3760,7 @@ func (m *Manager) KickedOutOfCommunity(id types.HexBytes, spectateMode bool) (*C
37573760
community.Spectate()
37583761
}
37593762

3760-
if err = m.persistence.SaveCommunity(community); err != nil {
3763+
if err = m.SaveCommunity(community); err != nil {
37613764
return nil, err
37623765
}
37633766

@@ -3778,7 +3781,7 @@ func (m *Manager) AddMemberOwnerToCommunity(communityID types.HexBytes, pk *ecds
37783781
return nil, err
37793782
}
37803783

3781-
err = m.persistence.SaveCommunity(community)
3784+
err = m.SaveCommunity(community)
37823785
if err != nil {
37833786
return nil, err
37843787
}
@@ -3861,7 +3864,7 @@ func (m *Manager) AddRoleToMember(request *requests.AddRoleToMember) (*Community
38613864
return nil, err
38623865
}
38633866

3864-
err = m.persistence.SaveCommunity(community)
3867+
err = m.SaveCommunity(community)
38653868
if err != nil {
38663869
return nil, err
38673870
}
@@ -3895,7 +3898,7 @@ func (m *Manager) RemoveRoleFromMember(request *requests.RemoveRoleFromMember) (
38953898
return nil, err
38963899
}
38973900

3898-
err = m.persistence.SaveCommunity(community)
3901+
err = m.SaveCommunity(community)
38993902
if err != nil {
39003903
return nil, err
39013904
}
@@ -3993,6 +3996,10 @@ func (m *Manager) GetByID(id []byte) (*Community, error) {
39933996
return community, nil
39943997
}
39953998

3999+
func (m *Manager) GetByIDReadonly(id []byte) (ReadonlyCommunity, error) {
4000+
return m.GetByIDStringReadonly(types.EncodeHex(id))
4001+
}
4002+
39964003
func (m *Manager) GetByIDString(idString string) (*Community, error) {
39974004
id, err := types.DecodeHex(idString)
39984005
if err != nil {
@@ -4001,6 +4008,21 @@ func (m *Manager) GetByIDString(idString string) (*Community, error) {
40014008
return m.GetByID(id)
40024009
}
40034010

4011+
func (m *Manager) GetByIDStringReadonly(idString string) (ReadonlyCommunity, error) {
4012+
cached := m.cache.Get(idString)
4013+
if cached != nil {
4014+
return cached.Value(), nil
4015+
}
4016+
4017+
community, err := m.GetByIDString(idString)
4018+
if err != nil {
4019+
return nil, err
4020+
}
4021+
m.cache.Set(idString, ReadonlyCommunity(community), ttlcache.DefaultTTL)
4022+
4023+
return ReadonlyCommunity(community), err
4024+
}
4025+
40044026
func (m *Manager) GetCommunityShard(communityID types.HexBytes) (*wakuv2.Shard, error) {
40054027
return m.persistence.GetCommunityShard(communityID)
40064028
}
@@ -4130,7 +4152,7 @@ func (m *Manager) RequestsToJoinForCommunityAwaitingAddresses(id types.HexBytes)
41304152
}
41314153

41324154
func (m *Manager) CanPost(pk *ecdsa.PublicKey, communityID string, chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) {
4133-
community, err := m.GetByIDString(communityID)
4155+
community, err := m.GetByIDStringReadonly(communityID)
41344156
if err != nil {
41354157
return false, err
41364158
}
@@ -4494,7 +4516,7 @@ func (m *Manager) SetCommunityActiveMembersCount(communityID string, activeMembe
44944516
}
44954517

44964518
if updated {
4497-
if err = m.persistence.SaveCommunity(community); err != nil {
4519+
if err = m.SaveCommunity(community); err != nil {
44984520
return err
44994521
}
45004522

@@ -4543,7 +4565,7 @@ func (m *Manager) SaveAndPublish(community *Community) error {
45434565
}
45444566

45454567
func (m *Manager) saveAndPublish(community *Community) error {
4546-
err := m.persistence.SaveCommunity(community)
4568+
err := m.SaveCommunity(community)
45474569
if err != nil {
45484570
return err
45494571
}
@@ -4898,7 +4920,7 @@ func (m *Manager) handleCommunityEvents(community *Community) error {
48984920
community.config.EventsData = nil // clear events, they are already applied
48994921
community.increaseClock()
49004922

4901-
err = m.persistence.SaveCommunity(community)
4923+
err = m.SaveCommunity(community)
49024924
if err != nil {
49034925
return err
49044926
}
@@ -5037,6 +5059,7 @@ func (m *Manager) GetCommunityRequestsToJoinWithRevealedAddresses(communityID ty
50375059
}
50385060

50395061
func (m *Manager) SaveCommunity(community *Community) error {
5062+
m.cache.Delete(community.IDString())
50405063
return m.persistence.SaveCommunity(community)
50415064
}
50425065

protocol/messenger.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2385,7 +2385,7 @@ func (m *Messenger) updateChatFirstMessageTimestamp(chat *Chat, timestamp uint32
23852385
return nil
23862386
}
23872387

2388-
community, err := m.communitiesManager.GetByIDString(chat.CommunityID)
2388+
community, err := m.communitiesManager.GetByIDStringReadonly(chat.CommunityID)
23892389
if err != nil {
23902390
return err
23912391
}

protocol/messenger_handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2198,7 +2198,7 @@ func (m *Messenger) handleChatMessage(state *ReceivedMessageState, forceSeen boo
21982198
return err
21992199
}
22002200

2201-
community, err := m.GetCommunityByID(communityID)
2201+
community, err := m.communitiesManager.GetByIDReadonly(communityID)
22022202
if err != nil {
22032203
return err
22042204
}

0 commit comments

Comments
 (0)