Skip to content

Cache size and eviction

The query cache is bounded by cacheSizeBytes, 100 MiB by default; past it, the lists fetched longest ago are deleted first. A list a live reader shows is kept while it is shown, and the mutation queue is never evicted. The samples write both bounds out at their defaults:

From the samples: SampleSupabaseClient.kt ยท ClientSettings.swift

// Cached query results, by the length of their answers: past it, the longest-fetched go.
cacheSizeBytes =
    QUERY_CACHE_SIZE_BYTES // the default; Offline.CACHE_SIZE_UNLIMITED never evicts
// Downloaded photos: past it, the least recently used go, never one in use.
fileCacheSizeBytes = PHOTO_CACHE_SIZE_BYTES // the default
/// The most cached query results may take on disk before the ones fetched longest ago are
/// evicted: 100 MiB, the default. Rows a live read shows are never evicted.
static let queryCacheSize = SupabaseOfflineClient.CacheSize.bytes(100 * 1_024 * 1_024)

/// The most downloaded photos may take on disk before the least recently used are deleted:
/// 256 MiB, the default. Photos are the large part; `.unlimited` would keep every one.
static let photoCacheSize = SupabaseOfflineClient.CacheSize.bytes(256 * 1_024 * 1_024)

What is measured and when

The bound counts the length of the cached responses, the JSON text PostgREST sent, summed over every cached list. It does not count the database file, nor the queue, the rejected list or the library's own records, which eviction never touches (the rejected list keeps its newest 100 entries). After a response of 4,096 characters or more, and after every 32nd response, the library sums the cached responses; over the bound, it deletes the lists fetched longest ago, ten at a time, until the sum is 50 MB below the bound (down to the bound itself when the bound is 50 MB or less), so a burst of reads does not start a pass on every read. Offline.CACHE_SIZE_UNLIMITED (-1) turns eviction off; any other value below 4 KiB counts as 4 KiB.

What is evicted

The lists fetched longest ago, by the time the server sent them; a list a write marked stale keeps its place by that time too. Up to 500 lists a live reader shows are kept whatever their age, and the oldest list nobody reads goes in their place, so a reader never drops to "no data". Past 500 live lists, or for a reader that starts while a pass is deleting, a list a reader needs can go: a CacheFirstThenNetwork reader then fetches it again, and a CacheOnly reader shows no data.

SQLite keeps the pages a delete frees for its next writes, so the database file does not shrink when lists are evicted, and it can be larger than the bound; clearLocalData() rewrites the database, which returns the space.

The file cache

Downloaded Storage files have a bound of their own, fileCacheSizeBytes, 256 MiB by default. When a download passes it, the least recently used files are deleted until the cache is a tenth below the bound. A file being read, and a file used in the last 30 seconds, are kept; a file's last use is recorded on disk, so it survives a restart. CACHE_SIZE_UNLIMITED turns this eviction off, and any other value below zero counts as zero. Temporary download files a crash left behind are deleted once they are more than a day old. See Storage caching.