From 0726c29528b412bbac34dd9d6eb609cd8da7135b Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Mon, 4 Aug 2025 11:01:16 -0700 Subject: [PATCH] Swap between two log buffers to save on copying --- .../securesms/logging/PersistentLogger.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt b/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt index c5f088f917..789c06129e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt @@ -121,11 +121,11 @@ class PersistentLogger private constructor(application: Application) : Log.Logge ) : Thread("signal-logger") { private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS zzz", Locale.US) - private val buffer = mutableListOf() override fun run() { + var buffer = mutableListOf() while (true) { - requests.blockForRequests(buffer) + buffer = requests.blockForRequests(buffer) db.logs.insert(buffer.asSequence().flatMap { requestToEntries(it) }, System.currentTimeMillis()) buffer.clear() requests.notifyFlushed() @@ -172,7 +172,8 @@ class PersistentLogger private constructor(application: Application) : Log.Logge } private class LogRequests { - val logs = mutableListOf() + // Mutable because it gets replaced in blockForRequests, to save a copy operation. + var logs = mutableListOf() val logLock = Object() var flushed = false @@ -186,18 +187,21 @@ class PersistentLogger private constructor(application: Application) : Log.Logge } /** - * Blocks until requests are available. When they are, the [buffer] will be populated with all pending requests. - * Note: This method gets hit a *lot*, which is why we're using a buffer instead of spamming out new lists every time. + * Blocks until requests are available. When they are, returns all pending requests and swaps `swapBuffer` with the internal storage for future requests. + * + * Note: This method gets hit a *lot*, which is why we're using a pair of buffers instead of spamming out new lists every time. + * `swapBuffer` should already be empty upon entry to this method. */ - fun blockForRequests(buffer: MutableList) { + fun blockForRequests(swapBuffer: MutableList): MutableList { synchronized(logLock) { while (logs.isEmpty()) { logLock.wait() } - buffer.addAll(logs) - logs.clear() + val result = logs + logs = swapBuffer flushed = false + return result } }