That fuck shit the fascists are using
at master 90 lines 2.9 kB view raw
1package org.tm.archive.database 2 3import androidx.annotation.VisibleForTesting 4import org.tm.archive.database.model.PendingRetryReceiptModel 5import org.tm.archive.recipients.RecipientId 6import org.tm.archive.util.FeatureFlags 7 8/** 9 * A write-through cache for [PendingRetryReceiptTable]. 10 * 11 * We have to read from this cache every time we process an incoming message. As a result, it's a very performance-sensitive operation. 12 * 13 * This cache is very similar to our job storage cache or our key-value store, in the sense that the first access of it will fetch all data from disk so all 14 * future reads can happen in memory. 15 */ 16class PendingRetryReceiptCache @VisibleForTesting constructor( 17 private val database: PendingRetryReceiptTable = SignalDatabase.pendingRetryReceipts 18) { 19 20 private val pendingRetries: MutableMap<RemoteMessageId, PendingRetryReceiptModel> = HashMap() 21 private var populated: Boolean = false 22 23 fun insert(author: RecipientId, authorDevice: Int, sentTimestamp: Long, receivedTimestamp: Long, threadId: Long) { 24 if (!FeatureFlags.retryReceipts()) return 25 ensurePopulated() 26 val model: PendingRetryReceiptModel = database.insert(author, authorDevice, sentTimestamp, receivedTimestamp, threadId) 27 synchronized(pendingRetries) { 28 val key = RemoteMessageId(author, sentTimestamp) 29 val existing: PendingRetryReceiptModel? = pendingRetries[key] 30 31 // We rely on db unique constraint and auto-incrementing ids for conflict resolution here. 32 if (existing == null || existing.id < model.id) { 33 pendingRetries[key] = model 34 } 35 } 36 } 37 38 fun get(author: RecipientId, sentTimestamp: Long): PendingRetryReceiptModel? { 39 if (!FeatureFlags.retryReceipts()) return null 40 ensurePopulated() 41 42 synchronized(pendingRetries) { 43 return pendingRetries[RemoteMessageId(author, sentTimestamp)] 44 } 45 } 46 47 fun getOldest(): PendingRetryReceiptModel? { 48 if (!FeatureFlags.retryReceipts()) return null 49 ensurePopulated() 50 51 synchronized(pendingRetries) { 52 return pendingRetries.values.minByOrNull { it.receivedTimestamp } 53 } 54 } 55 56 fun delete(model: PendingRetryReceiptModel) { 57 if (!FeatureFlags.retryReceipts()) return 58 ensurePopulated() 59 60 synchronized(pendingRetries) { 61 pendingRetries.remove(RemoteMessageId(model.author, model.sentTimestamp)) 62 } 63 database.delete(model) 64 } 65 66 fun clear() { 67 if (!FeatureFlags.retryReceipts()) return 68 69 synchronized(pendingRetries) { 70 pendingRetries.clear() 71 populated = false 72 } 73 } 74 75 private fun ensurePopulated() { 76 if (!populated) { 77 synchronized(pendingRetries) { 78 if (!populated) { 79 database.all.forEach { model -> 80 pendingRetries[RemoteMessageId(model.author, model.sentTimestamp)] = model 81 } 82 83 populated = true 84 } 85 } 86 } 87 } 88 89 data class RemoteMessageId(val author: RecipientId, val sentTimestamp: Long) 90}