From 67ae678137fe3bc8b31ce5f925f7ae40962e6132 Mon Sep 17 00:00:00 2001 From: Malcolm Smith Date: Wed, 6 Jan 2021 21:12:59 +0100 Subject: [PATCH] storage/db: use faster JSON encoder settings when wallet is encrypted The standard json module has an optimized C encoder, but that doesn't currently support indentation. So if you request indentation, it falls back on the slower Python encoder. Readability doesn't matter for encrypted wallets, so this disables indentation when the wallet is encrypted. ----- based on https://github.com/Electron-Cash/Electron-Cash/commit/b2399b6a3e3e39ddd82ffc432bb1ca07f2aab454 For a large encrypted wallet, compare: before change: JsonDB.dump 1.3153 sec zlib.compress 1.281 sec ECPubkey.encrypt_message 0.1744 sec after change: JsonDB.dump 0.5059 sec zlib.compress 1.3120 sec ECPubkey.encrypt_message 0.1630 sec Co-authored-by: SomberNight --- electrum/json_db.py | 12 ++++++++++-- electrum/storage.py | 3 +-- electrum/wallet_db.py | 4 +++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/electrum/json_db.py b/electrum/json_db.py index 69b7f216b..83154536b 100644 --- a/electrum/json_db.py +++ b/electrum/json_db.py @@ -193,8 +193,16 @@ class JsonDB(Logger): return False @locked - def dump(self): - return json.dumps(self.data, indent=4, sort_keys=True, cls=JsonDBJsonEncoder) + def dump(self, *, human_readable: bool = True) -> str: + """Serializes the DB as a string. + 'human_readable': makes the json indented and sorted, but this is ~2x slower + """ + return json.dumps( + self.data, + indent=4 if human_readable else None, + sort_keys=bool(human_readable), + cls=JsonDBJsonEncoder, + ) def _should_convert_to_stored_dict(self, key) -> bool: return True diff --git a/electrum/storage.py b/electrum/storage.py index ab67fe643..652b5330a 100644 --- a/electrum/storage.py +++ b/electrum/storage.py @@ -78,8 +78,7 @@ class WalletStorage(Logger): def read(self): return self.decrypted if self.is_encrypted() else self.raw - @profiler - def write(self, data): + def write(self, data: str) -> None: s = self.encrypt_before_writing(data) temp_path = "%s.tmp.%s" % (self.path, os.getpid()) with open(temp_path, "w", encoding='utf-8') as f: diff --git a/electrum/wallet_db.py b/electrum/wallet_db.py index f60ec2263..b37a8b035 100644 --- a/electrum/wallet_db.py +++ b/electrum/wallet_db.py @@ -1238,13 +1238,15 @@ class WalletDB(JsonDB): with self.lock: self._write(storage) + @profiler def _write(self, storage: 'WalletStorage'): if threading.currentThread().isDaemon(): self.logger.warning('daemon thread cannot write db') return if not self.modified(): return - storage.write(self.dump()) + json_str = self.dump(human_readable=not storage.is_encrypted()) + storage.write(json_str) self.set_modified(False) def is_ready_to_be_used_by_wallet(self):