Gc database

This commit is contained in:
Koitharu
2022-05-16 15:07:34 +03:00
parent a9f3ab259a
commit bd29c64370
7 changed files with 73 additions and 21 deletions

View File

@@ -7,9 +7,13 @@ import android.content.Context
import android.os.Bundle
import android.util.ArrayMap
import androidx.room.InvalidationTracker
import androidx.room.withTransaction
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.TABLE_FAVOURITES
import org.koitharu.kotatsu.core.db.TABLE_FAVOURITE_CATEGORIES
import org.koitharu.kotatsu.core.db.TABLE_HISTORY
@@ -27,7 +31,10 @@ class SyncController(
} else {
TimeUnit.MINUTES.toMillis(4)
}
private val mutex = Mutex()
private val jobs = ArrayMap<String, Job>(2)
private val defaultGcPeriod: Long // gc period if sync disabled
get() = TimeUnit.DAYS.toMillis(2)
override fun onInvalidated(tables: MutableSet<String>) {
requestSync(
@@ -48,36 +55,49 @@ class SyncController(
}
suspend fun requestFullSync() = withContext(Dispatchers.Default) {
requestSyncImpl(favourites = true, history = true)
requestSyncImpl(favourites = true, history = true, db = null)
}
suspend fun requestFullSyncAndGc(database: MangaDatabase) = withContext(Dispatchers.Default) {
requestSyncImpl(favourites = true, history = true, db = database)
}
private fun requestSync(favourites: Boolean, history: Boolean) = processLifecycleScope.launch(Dispatchers.Default) {
requestSyncImpl(favourites, history)
requestSyncImpl(favourites = favourites, history = history, db = null)
}
@Synchronized
private fun requestSyncImpl(favourites: Boolean, history: Boolean) {
private suspend fun requestSyncImpl(favourites: Boolean, history: Boolean, db: MangaDatabase?) = mutex.withLock {
if (!favourites && !history) {
return
}
val account = peekAccount() ?: return
if (!ContentResolver.getMasterSyncAutomatically()) {
val account = peekAccount()
if (account == null || !ContentResolver.getMasterSyncAutomatically()) {
db?.gc(favourites, history)
return
}
var gcHistory = false
var gcFavourites = false
if (favourites) {
scheduleSync(account, AUTHORITY_FAVOURITES)
if (ContentResolver.getSyncAutomatically(account, AUTHORITY_FAVOURITES)) {
scheduleSync(account, AUTHORITY_FAVOURITES)
} else {
gcFavourites = true
}
}
if (history) {
scheduleSync(account, AUTHORITY_HISTORY)
if (ContentResolver.getSyncAutomatically(account, AUTHORITY_HISTORY)) {
scheduleSync(account, AUTHORITY_HISTORY)
} else {
gcHistory = true
}
}
if (db != null && (gcHistory || gcFavourites)) {
db.gc(gcFavourites, gcHistory)
}
}
private fun scheduleSync(account: Account, authority: String) {
if (
!ContentResolver.getSyncAutomatically(account, AUTHORITY_FAVOURITES) ||
ContentResolver.isSyncActive(account, authority) ||
ContentResolver.isSyncPending(account, authority)
) {
if (ContentResolver.isSyncActive(account, authority) || ContentResolver.isSyncPending(account, authority)) {
return
}
val job = jobs[authority]
@@ -105,4 +125,15 @@ class SyncController(
private fun peekAccount(): Account? {
return am.getAccountsByType(accountType).firstOrNull()
}
private suspend fun MangaDatabase.gc(favourites: Boolean, history: Boolean) = withTransaction {
val deletedAt = System.currentTimeMillis() - defaultGcPeriod
if (history) {
historyDao.gc(deletedAt)
}
if (favourites) {
favouritesDao.gc(deletedAt)
favouriteCategoriesDao.gc(deletedAt)
}
}
}

View File

@@ -21,6 +21,7 @@ import org.koitharu.kotatsu.utils.ext.parseJsonOrNull
import org.koitharu.kotatsu.utils.ext.toContentValues
import org.koitharu.kotatsu.utils.ext.toJson
import org.koitharu.kotatsu.utils.ext.toRequestBody
import java.util.concurrent.TimeUnit
const val AUTHORITY_HISTORY = "org.koitharu.kotatsu.history"
const val AUTHORITY_FAVOURITES = "org.koitharu.kotatsu.favourites"
@@ -43,6 +44,8 @@ class SyncHelper(
.addInterceptor(GZipInterceptor())
.build()
private val baseUrl = context.getString(R.string.url_sync_server)
private val defaultGcPeriod: Long // gc period if sync enabled
get() = TimeUnit.DAYS.toMillis(4)
fun syncFavourites(syncResult: SyncResult) {
val data = JSONObject()
@@ -61,6 +64,7 @@ class SyncHelper(
val favouritesResult = upsertFavourites(response.getJSONArray(TABLE_FAVOURITES), timestamp)
syncResult.stats.numDeletes += favouritesResult.first().count?.toLong() ?: 0L
syncResult.stats.numInserts += favouritesResult.drop(1).sumOf { it.count?.toLong() ?: 0L }
gcFavourites()
}
fun syncHistory(syncResult: SyncResult) {
@@ -78,6 +82,7 @@ class SyncHelper(
)
syncResult.stats.numDeletes += result.first().count?.toLong() ?: 0L
syncResult.stats.numInserts += result.drop(1).sumOf { it.count?.toLong() ?: 0L }
gcHistory()
}
private fun upsertHistory(json: JSONArray, timestamp: Long): Array<ContentProviderResult> {
@@ -238,6 +243,21 @@ class SyncHelper(
return requireNotNull(tag)
}
private fun gcFavourites() {
val deletedAt = System.currentTimeMillis() - defaultGcPeriod
val selection = "deleted_at != 0 AND deleted_at < ?"
val args = arrayOf(deletedAt.toString())
provider.delete(uri(AUTHORITY_FAVOURITES, TABLE_FAVOURITES), selection, args)
provider.delete(uri(AUTHORITY_FAVOURITES, TABLE_FAVOURITE_CATEGORIES), selection, args)
}
private fun gcHistory() {
val deletedAt = System.currentTimeMillis() - defaultGcPeriod
val selection = "deleted_at != 0 AND deleted_at < ?"
val args = arrayOf(deletedAt.toString())
provider.delete(uri(AUTHORITY_HISTORY, TABLE_HISTORY), selection, args)
}
private fun ContentProviderClient.query(authority: String, table: String): Cursor {
val uri = uri(authority, table)
return query(uri, null, null, null, null)