# How Mole's Caching System Speeds Up Disk Analysis

> Discover how Mole's caching system accelerates disk analysis by storing filesystem scan results in binary files, ensuring validity and avoiding redundant rescans.

- Repository: [Tw93/Mole](https://github.com/tw93/Mole)
- Tags: internals
- Published: 2026-03-20

---

**Mole's caching system stores filesystem scan results in `~/.cache/mole` using xxHash-64 keyed binary files, validating them for up to 7 days while detecting directory modifications to avoid unnecessary rescans.**

Mole is an open-source disk analysis tool by [tw93/Mole](https://github.com/tw93/Mole) that builds detailed views of filesystem trees, large files, and storage totals. Because full directory walks can be expensive on large drives, Mole's caching system persists per-directory results and reuses them when possible. The implementation lives primarily in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go), with integration logic spread across [`cmd/analyze/scanner.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/scanner.go) and [`cmd/analyze/main.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/main.go).

## Cache Storage Location and Structure

### Where Mole Stores Cache Files

Mole creates a dedicated cache directory at `~/.cache/mole` on first run. The `getCacheDir()` function in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go) (lines 65-71) ensures this directory exists before any write operations.

Each scanned path receives its own cache file named `<hash>.cache`, where the hash is a **xxHash-64** of the absolute path string. The `getCachePath()` function (lines 78-84) generates these filenames consistently.

Additionally, Mole maintains an [`overview.json`](https://github.com/tw93/Mole/blob/main/overview.json) file in the same directory for quick size lookups of top-level folders. This is managed separately from the per-path caches.

### The Cache Entry Data Structure

Each `.cache` file stores a serialized `cacheEntry` struct defined in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go):

```go
type cacheEntry struct {
    Entries    []dirEntry   // all scanned directories
    LargeFiles []fileEntry  // files > threshold
    TotalSize  int64        // bytes of everything under the path
    TotalFiles int64        // file count
    ModTime    time.Time    // modification time of the directory at scan time
    ScanTime   time.Time    // when the scan finished
}

```

The `saveCacheToDisk()` function (lines 57-85) writes this structure using Go's `gob` encoding for fast binary serialization.

## Cache Validation and Expiration Logic

Mole's caching system implements a multi-layered validation strategy in `loadCacheFromDisk()` (lines 8-36) to balance performance with accuracy.

### The 7-Day Age Limit

By default, **any cache older than 7 days is automatically rejected**, regardless of directory state. This hard limit prevents displaying stale data from long-obsolete scans. The check compares `ScanTime` against the current time, rejecting entries where `scanAge > 7*24h`.

### Directory Modification Detection

If the cache is younger than 7 days, Mole checks whether the directory has changed since the scan. It compares the current directory `ModTime` against the `ModTime` stored in the cache entry.

If the current modification time is newer than the cached value, the cache is **usually** invalid.

### Grace Windows and Reuse Policies

To prevent excessive invalidations from minor, rapid changes, Mole applies two configurable windows defined in [`cmd/analyze/constants.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/constants.go) (lines 20-21):

- **`cacheModTimeGrace`**: A tolerance period for directory modifications. If the directory changed within this grace period, the cache remains valid.
- **`cacheReuseWindow`**: If this is set and the scan age is within this window, Mole reuses the cache even if the directory modified time suggests change.

The validation logic in `loadCacheFromDisk()` implements this cascade:

```go
if info.ModTime().After(entry.ModTime) {
    if cacheModTimeGrace <= 0 || info.ModTime().Sub(entry.ModTime) > cacheModTimeGrace {
        if cacheReuseWindow <= 0 || scanAge > cacheReuseWindow {
            return nil, fmt.Errorf("cache expired: directory modified")
        }
    }
}

```

## Performance Optimizations

### Stale Cache for Instant UI Rendering

When starting the TUI mode via `runTUIMode()` in [`cmd/analyze/main.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/main.go) (line 66), Mole spawns `prefetchOverviewCache()` to load data immediately. The `loadStaleCacheFromDisk()` function (lines 38-55) implements a "stale-while-revalidate" pattern:

- It ignores the strict 7-day age limit and modification checks
- It only verifies the cache is younger than `staleCacheTTL` (approximately 5 seconds)
- If valid, the UI renders instantly while a background scan refreshes the data

This ensures users see a directory tree immediately, even if it's slightly outdated, rather than waiting for a full filesystem walk.

### Overview Snapshots for Quick Size Lookups

For the overview mode that lists top-level directories, Mole maintains a separate [`overview.json`](https://github.com/tw93/Mole/blob/main/overview.json) snapshot. The `loadStoredOverviewSize()` function (lines 6-11) checks this JSON map, which stores `size` and `updated` timestamps.

If the snapshot is younger than `overviewCacheTTL` (approximately 30 minutes), Mole returns the stored size without touching the per-path cache or scanning the directory. After a fresh scan completes, `storeOverviewSize()` (lines 15-30) automatically updates this snapshot.

## How the Analyze Command Integrates Caching

The caching system is tightly integrated into the analysis workflow across three main components:

1. **Prefetched Loading**: When `runTUIMode()` starts in [`cmd/analyze/main.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/main.go) (lines 65-70), it immediately calls `prefetchOverviewCache()` to load any available cached data before the UI renders.

2. **Scan-Time Resolution**: In [`cmd/analyze/scanner.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/scanner.go), the scanner first attempts `loadCacheFromDisk(path)` (lines 351-356). 
   - **Cache Hit**: The UI populates instantly with the cached `cacheEntry` data.
   - **Cache Miss**: The scanner performs a full filesystem walk, then calls `saveCacheToDisk()` (lines 57-85) to persist the new results.

3. **Overview Updates**: After a successful scan, the system calls `storeOverviewSize()` (lines 61-62) to update the [`overview.json`](https://github.com/tw93/Mole/blob/main/overview.json) snapshot, ensuring subsequent top-level listings remain fast.

## Clearing and Invalidating the Cache

Users can clear Mole's caching system through several methods:

**Manual deletion** of the entire cache directory:

```bash
rm -rf "${HOME}/.cache/mole"

```

**Using Mole's built-in purge command**:

```bash
mo purge

```

This executes the [`bin/purge.sh`](https://github.com/tw93/Mole/blob/main/bin/purge.sh) script (lines 102-114), which specifically removes cache files while preserving the directory structure.

**Update-triggered clearing**: When running `mo update` or reinstalling Mole, the installation process ensures a clean cache directory to prevent version incompatibilities.

## Summary

- **Mole's caching system** stores disk analysis results in `~/.cache/mole` using xxHash-64 keyed binary files encoded with Go's `gob` format.
- Each cache entry contains the full directory tree, large file lists, totals, and modification timestamps, defined in the `cacheEntry` struct in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go).
- **Validation logic** rejects caches older than 7 days or those where the directory has been modified outside the grace window, with configurable tolerance via `cacheModTimeGrace` and `cacheReuseWindow`.
- **Performance features** include stale-cache loading for instant UI rendering (5-second tolerance) and an [`overview.json`](https://github.com/tw93/Mole/blob/main/overview.json) snapshot for 30-minute fast size lookups of top-level directories.
- The analyze command integrates caching via `loadCacheFromDisk()` in [`cmd/analyze/scanner.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/scanner.go), falling back to full scans that automatically persist via `saveCacheToDisk()`.
- Users can invalidate caches manually, via `mo purge`, or through updates that clean the `~/.cache/mole` directory.

## Frequently Asked Questions

### Where does Mole store its cache files?

Mole stores all cache files in the `~/.cache/mole` directory. The `getCacheDir()` function in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go) creates this directory automatically if it doesn't exist. Individual scan results are stored as `<hash>.cache` files where the hash is a xxHash-64 of the absolute path, while overview snapshots live in [`overview.json`](https://github.com/tw93/Mole/blob/main/overview.json).

### How long does Mole's cache remain valid?

By default, **Mole's cache remains valid for up to 7 days**. However, the cache also becomes invalid immediately if the directory's modification time changes outside the configured grace window (`cacheModTimeGrace`). Additionally, the overview snapshot used for quick size lookups expires after approximately 30 minutes (`overviewCacheTTL`), while stale caches used for instant UI rendering last only about 5 seconds (`staleCacheTTL`).

### Can I force Mole to ignore the cache?

While there is no public command-line flag exposed in the current version, you can force Mole to ignore the cache by **removing the specific cache file** before running the analysis. Locate the cache file by computing the xxHash-64 of your target path, then delete `${HOME}/.cache/mole/<hash>.cache`. Alternatively, running `mo purge` clears all caches, ensuring the next analysis performs a fresh scan.

### What happens if I modify files while Mole is running?

If files are modified while Mole is running, the **stale cache mechanism** ensures the UI remains responsive. When the TUI launches, it first loads any available cache (even if slightly outdated) to render the initial view instantly. A background scan then refreshes the data asynchronously. For subsequent runs, the `loadCacheFromDisk()` function detects the directory modification via `ModTime` comparison and invalidates the cache unless the change falls within the grace window, ensuring you don't see stale data for long.