From 0a108dd849226c79da7f53fe64c9a21536dcfc2b Mon Sep 17 00:00:00 2001 From: Eric Mastro Date: Thu, 15 Apr 2021 13:11:51 +1000 Subject: [PATCH] feat: Add libstatus contacts caching Fixes #2131. After some heavy profiling, it became clear that sending of each message was causing a fetch to get all contacts from status-go. This was incurring a minimum of a 0.03s delay for each fetch, which was causing a bottleneck each time it was called for various operations throughout the codebase. This code addds a layer of threadsafe caching to the contacts call, such that only the first call to contacts fetching will incur the delay, as well as every fetch after a contacts CUD operation. --- src/status/libstatus/contacts.nim | 33 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/status/libstatus/contacts.nim b/src/status/libstatus/contacts.nim index 025d32ac01..f384e76de0 100644 --- a/src/status/libstatus/contacts.nim +++ b/src/status/libstatus/contacts.nim @@ -1,7 +1,12 @@ -import json, strmisc +import json, strmisc, atomics import core, utils, types, settings from ../profile/profile import Profile +var + contacts {.threadvar.}: JsonNode + contactsInited {.threadvar.}: bool + dirty: Atomic[bool] + # TODO: remove Profile from here proc blockContact*(contact: Profile): string = callPrivateRPC("blockContact".prefix, %* [ @@ -16,13 +21,22 @@ proc blockContact*(contact: Profile): string = proc getContactByID*(id: string): string = result = callPrivateRPC("getContactByID".prefix, %* [id]) + dirty.store(true) proc getContacts*(): JsonNode = - let payload = %* [] - let response = callPrivateRPC("contacts".prefix, payload).parseJson - if response["result"].kind == JNull: - return %* [] - return response["result"] + let cacheIsDirty = (not contactsInited) or dirty.load + if not cacheIsDirty: + result = contacts + else: + let payload = %* [] + let response = callPrivateRPC("contacts".prefix, payload).parseJson + if response["result"].kind == JNull: + result = %* [] + else: + result = response["result"] + dirty.store(false) + contacts = result + contactsInited = true proc saveContact*(id: string, ensVerified: bool, ensName: string, alias: string, identicon: string, thumbnail: string, systemTags: seq[string], localNickname: string): string = let payload = %* [{ @@ -35,7 +49,10 @@ proc saveContact*(id: string, ensVerified: bool, ensName: string, alias: string, "systemTags": systemTags, "localNickname": localNickname }] - callPrivateRPC("saveContact".prefix, payload) + # TODO: StatusGoError handling + result = callPrivateRPC("saveContact".prefix, payload) + dirty.store(true) proc requestContactUpdate*(publicKey: string): string = - callPrivateRPC("sendContactUpdate".prefix, %* [publicKey, "", ""]) \ No newline at end of file + result = callPrivateRPC("sendContactUpdate".prefix, %* [publicKey, "", ""]) + dirty.store(true)