fix cache cleanup deleting more statuses than it should (#2348)
* fix cache cleanup deleting more statuses than it should * reset LOAD_AT_ONCE * improve tests * move cache clean code back to ViewModel
This commit is contained in:
parent
a4c2ca6cfc
commit
69bcc92c46
5 changed files with 118 additions and 42 deletions
|
@ -6,12 +6,11 @@ import com.keylesspalace.tusky.db.AppDatabase
|
|||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class CacheUpdater @Inject constructor(
|
||||
eventHub: EventHub,
|
||||
accountManager: AccountManager,
|
||||
private val accountManager: AccountManager,
|
||||
private val appDatabase: AppDatabase,
|
||||
gson: Gson
|
||||
) {
|
||||
|
@ -21,11 +20,6 @@ class CacheUpdater @Inject constructor(
|
|||
init {
|
||||
val timelineDao = appDatabase.timelineDao()
|
||||
|
||||
Schedulers.io().scheduleDirect {
|
||||
val olderThan = System.currentTimeMillis() - CLEANUP_INTERVAL
|
||||
appDatabase.timelineDao().cleanup(olderThan)
|
||||
}
|
||||
|
||||
disposable = eventHub.events.subscribe { event ->
|
||||
val accountId = accountManager.activeAccount?.id ?: return@subscribe
|
||||
when (event) {
|
||||
|
@ -61,8 +55,4 @@ class CacheUpdater @Inject constructor(
|
|||
.subscribeOn(Schedulers.io())
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CLEANUP_INTERVAL = TimeUnit.DAYS.toMillis(14)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,11 +43,14 @@ import com.keylesspalace.tusky.network.TimelineCases
|
|||
import com.keylesspalace.tusky.util.dec
|
||||
import com.keylesspalace.tusky.util.inc
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.rx3.await
|
||||
import retrofit2.HttpException
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.toDuration
|
||||
|
||||
/**
|
||||
* TimelineViewModel that caches all statuses in a local database
|
||||
|
@ -81,6 +84,16 @@ class CachedTimelineViewModel @Inject constructor(
|
|||
}
|
||||
.cachedIn(viewModelScope)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
delay(5.toDuration(DurationUnit.SECONDS)) // delay so the db is not locked during initial ui refresh
|
||||
accountManager.activeAccount?.id?.let { accountId ->
|
||||
db.timelineDao().cleanup(accountId, MAX_STATUSES_IN_CACHE)
|
||||
db.timelineDao().cleanupAccounts(accountId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun updatePoll(newPoll: Poll, status: StatusViewData.Concrete) {
|
||||
// handled by CacheUpdater
|
||||
}
|
||||
|
@ -207,4 +220,8 @@ class CachedTimelineViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_STATUSES_IN_CACHE = 1000
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ import com.keylesspalace.tusky.settings.PrefKeys
|
|||
import com.keylesspalace.tusky.viewdata.StatusViewData
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.rx3.asFlow
|
||||
import kotlinx.coroutines.rx3.await
|
||||
|
|
|
@ -98,8 +98,29 @@ AND serverId = :statusId"""
|
|||
)
|
||||
abstract fun delete(accountId: Long, statusId: String)
|
||||
|
||||
@Query("""DELETE FROM TimelineStatusEntity WHERE createdAt < :olderThan""")
|
||||
abstract fun cleanup(olderThan: Long)
|
||||
/**
|
||||
* Cleans the TimelineStatusEntity table from old status entries.
|
||||
* @param accountId id of the account for which to clean statuses
|
||||
* @param limit how many statuses to keep
|
||||
*/
|
||||
@Query(
|
||||
"""DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND serverId NOT IN
|
||||
(SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT :limit)
|
||||
"""
|
||||
)
|
||||
abstract suspend fun cleanup(accountId: Long, limit: Int)
|
||||
|
||||
/**
|
||||
* Cleans the TimelineAccountEntity table from accounts that are no longer referenced in the TimelineStatusEntity table
|
||||
* @param accountId id of the user account for which to clean timeline accounts
|
||||
*/
|
||||
@Query(
|
||||
"""DELETE FROM TimelineAccountEntity WHERE timelineUserId = :accountId AND serverId NOT IN
|
||||
(SELECT authorServerId FROM TimelineStatusEntity WHERE timelineUserId = :accountId)
|
||||
AND serverId NOT IN
|
||||
(SELECT reblogAccountId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND reblogAccountId IS NOT NULL)"""
|
||||
)
|
||||
abstract suspend fun cleanupAccounts(accountId: Long)
|
||||
|
||||
@Query(
|
||||
"""UPDATE TimelineStatusEntity SET poll = :poll
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue