perf(teacher): lower sync memory footprint
- Reduce sync parallelism 5 -> 2 to cap peak heap while bulk-fetching all departments for a period - Replace per-write rows (insert schedule/days/lessons separately) with a single @Transaction replaceSchedule() so Room invalidates observers once per department instead of ~4x each, cutting main-thread recompositions and intermediate allocations during the 38-department sync
This commit is contained in:
@@ -4,6 +4,7 @@ import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
@@ -38,6 +39,16 @@ interface TeacherScheduleDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertLessons(lessons: List<TeacherLessonEntity>)
|
||||
|
||||
@Transaction
|
||||
suspend fun replaceSchedule(schedule: TeacherScheduleEntity, days: List<TeacherDayEntity>, lessons: List<TeacherLessonEntity>) {
|
||||
val scheduleId = insertSchedule(schedule)
|
||||
val daysWithScheduleId = days.map { it.copy(scheduleId = scheduleId) }
|
||||
deleteDaysForSchedule(scheduleId)
|
||||
val dayIds = insertDays(daysWithScheduleId)
|
||||
val dayIdByDate = daysWithScheduleId.zip(dayIds).associate { (day, id) -> day.date to id }
|
||||
insertLessons(lessons.map { lesson -> lesson.copy(dayId = dayIdByDate.getValue(lesson.date)) })
|
||||
}
|
||||
|
||||
@Query(
|
||||
"SELECT teacher_days.* FROM teacher_days INNER JOIN teacher_schedules ON teacher_schedules.id = teacher_days.scheduleId " +
|
||||
"WHERE teacher_schedules.season = :season AND teacher_schedules.weekStart <= :weekStart " +
|
||||
|
||||
@@ -156,33 +156,15 @@ class TeacherScheduleRepositoryImpl(
|
||||
val html = VyatsuHttpClient.getBytes(url).toString(Charsets.UTF_8)
|
||||
val parsed = TeacherScheduleParser.parse(html)
|
||||
|
||||
val scheduleId = scheduleDao.insertSchedule(
|
||||
TeacherScheduleEntity(
|
||||
departmentId = target.departmentId,
|
||||
season = season,
|
||||
weekStart = target.weekStart,
|
||||
weekEnd = target.weekEnd,
|
||||
lastSyncedAt = now()
|
||||
)
|
||||
)
|
||||
replaceDays(scheduleId, parsed.days)
|
||||
val dayEntities = parsed.days.map {
|
||||
TeacherDayEntity(scheduleId = 0, date = it.date.toEpochDay())
|
||||
}
|
||||
|
||||
private suspend fun replaceDays(scheduleId: Long, days: List<Day>) {
|
||||
scheduleDao.deleteDaysForSchedule(scheduleId)
|
||||
val dayEntities = days.map {
|
||||
TeacherDayEntity(scheduleId = scheduleId, date = it.date.toEpochDay())
|
||||
}
|
||||
val dayIds = scheduleDao.insertDays(dayEntities)
|
||||
val dayIdByDate = dayEntities.zip(dayIds).associate { (day, id) ->
|
||||
LocalDate.ofEpochDay(day.date) to id
|
||||
}
|
||||
val lessons = days.flatMap { day ->
|
||||
val lessonEntities = parsed.days.flatMap { day ->
|
||||
day.intervals.flatMapIndexed { slotIndex, slot ->
|
||||
slot.lessons.mapIndexedNotNull { lessonIndex, lesson ->
|
||||
val teacher = lesson.teacher ?: return@mapIndexedNotNull null
|
||||
TeacherLessonEntity(
|
||||
dayId = dayIdByDate.getValue(day.date),
|
||||
dayId = 0,
|
||||
date = day.date.toEpochDay(),
|
||||
slotIndex = slotIndex,
|
||||
start = slot.start.toMinutesOfDay(),
|
||||
@@ -199,7 +181,17 @@ class TeacherScheduleRepositoryImpl(
|
||||
}
|
||||
}
|
||||
}
|
||||
scheduleDao.insertLessons(lessons)
|
||||
scheduleDao.replaceSchedule(
|
||||
TeacherScheduleEntity(
|
||||
departmentId = target.departmentId,
|
||||
season = season,
|
||||
weekStart = target.weekStart,
|
||||
weekEnd = target.weekEnd,
|
||||
lastSyncedAt = now()
|
||||
),
|
||||
dayEntities,
|
||||
lessonEntities
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun trimToRecent(keepDistinctPeriods: Int) {
|
||||
@@ -262,7 +254,7 @@ class TeacherScheduleRepositoryImpl(
|
||||
|
||||
companion object {
|
||||
private const val STALE_WINDOW_MS = 12 * 60 * 60 * 1000L
|
||||
private const val PARALLELISM = 5
|
||||
private const val PARALLELISM = 2
|
||||
private const val TAG = "TeacherScheduleRepo"
|
||||
private val RANGE_FMT = java.time.format.DateTimeFormatter.ofPattern("ddMMyyyy")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user