Skip to content

afpd: default dircache mode to ARC - #3265

Merged
andylemin merged 1 commit into
mainfrom
perf-dircache-arc-default
Aug 26, 2026
Merged

afpd: default dircache mode to ARC#3265
andylemin merged 1 commit into
mainfrom
perf-dircache-arc-default

Conversation

@andylemin

@andylemin andylemin commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

What changes

A configuration that says nothing about dircache mode now gets ARC instead of LRU. Explicit dircache mode = lru remains the opt-out and behaves exactly as before; explicit arc is unchanged. An invalid value now falls back to ARC (previously LRU), with the warning message updated to match.

ARC has shipped opt-in for a full release cycle and delivers 10-50% better hit ratios than LRU (2× on sequential scans). With the cache-correctness work merged, the conservative-default question flips: the safe choice is to give every server the well-tested fast path and let memory-constrained systems opt down.

Memory: what ARC actually costs

LRU and ARC use the same amount of memory for the same number of live entries. ARC can use up to 2× (~24 MB vs ~12 MB at the 64K default) because instead of dropping an evicted entry outright it may keep it as a ghost — signalled as expired, but retained — so a ghost that is referenced again is promoted back to a full entry without rebuilding it from disk. Ghosts that stay cold are truly dropped.

The man page entry previously overstated this as "ARC uses approximately 2× memory (~100% overhead)"; it now describes the ghost mechanics and frames 2× as the ceiling, not the steady state.

Defect → fix

change where
missing-key default lruarc; invalid-value fallback lruarc (warning text updated) libatalk/util/netatalk_conf.c
(default: *lru*)(default: *arc*); body rewritten with the ghost/promotion mechanics; recommendation reworded doc/manpages/man5/afp.conf.5.md
webmin default lruarc contrib/webmin_module/netatalk-lib.pl
generated afp.conf hardcoded dircache mode = ${AFP_DIRCACHE_MODE:-lru}, which would have shadowed the new compiled default in every container; now emits the key only when AFP_DIRCACHE_MODE is set (same idiom as the strict locking line in the same heredoc) distrib/docker/env_setup_netatalk.sh
NEWS entry NEWS.md

Behaviour changes

  • Stock install: LRU → ARC replacement policy; dircache memory ceiling rises from ~12 MB to ~24 MB at the default size (ghosts only, as they accrue).
  • Docker image with AFP_DIRCACHE_MODE unset: previously wrote an explicit lru into afp.conf; now inherits the compiled default (arc). CI legs set the variable explicitly and are unaffected.
  • Explicit settings everywhere: unchanged.

Testing

  • meson test (Alpine container, CI build flags): 3/3 suites, zero failures.
  • AFP spectest, ea=sys and ea=ad legs (single container, CI env): both exit 0, zero failures — both legs now exercise the ARC default continuously.

@andylemin

Copy link
Copy Markdown
Contributor Author

augment review

@augmentcode

augmentcode Bot commented Aug 24, 2026

Copy link
Copy Markdown

Looks like you're out of credits for this review. Head to your account settings to top up and keep reviews running. https://app.augmentcode.com/account/subscription

@andylemin

Copy link
Copy Markdown
Contributor Author

@rdmark ready for review

@rdmark rdmark left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds reasonable to make ARC the default now 👍

@andylemin

Copy link
Copy Markdown
Contributor Author

@dependabot rebase

@rdmark

rdmark commented Aug 25, 2026

Copy link
Copy Markdown
Member

@dependabot rebase

I do this sometimes too on my own PRs :-D

ARC delivers 10-50% better hit ratios than LRU (2x on sequential
scans) and has shipped opt-in for a full release cycle. ARC can use
up to 2x the memory (~24 MB vs ~12 MB at the 64K default): evicted
entries may be retained as ghosts for instant re-promotion; cold
ghosts are dropped. With the correctness work merged the
conservative-default question flips: a config that says nothing now
gets the well-tested fast path, and memory-constrained systems opt
down with 'dircache mode = lru'.

The docker entrypoint's generated afp.conf now emits 'dircache mode'
only when AFP_DIRCACHE_MODE is set, so containers inherit the
compiled default instead of a hardcoded fallback.
@andylemin
andylemin force-pushed the perf-dircache-arc-default branch from 3d02d96 to b8b5655 Compare August 26, 2026 13:23
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

📊 Performance Dashboard

Commit: b8b56556d253a83d94c79b94f3c4b4cfd0a11f46

🔥 Spectest (AFP 3.4) - FlameGraph

Netatalk Code-time: 3.7% · Runtime: 60s · Stacks: 744

🔥 Click the preview to open the interactive flamegraph (zoom + search).

Flamegraph preview

🔝 Top 10 leaf functions
Function Samples
_raw_spin_unlock_irqrestore 111356035
do_syscall_64 85997730
[libsqlite3.so.3.53.4] 82690125
__cp_end 65049565
finish_task_switch.isra.0 47409005
afpd 23153235
kmem_cache_alloc_noprof 19845630
__raw_callee_save___pv_queued_spin_unlock 18743095
perf_syscall_enter 17640560
folio_unlock 17640560

📈 Speedtest (AFP 3.4) - PerfGraph

Speedtest throughput

Peak Read: 6723 MB/s (-6.8% vs hist avg 7212.7 MB/s; min 5963 / max 9526 over 27 PRs)
Peak Write: 1438 MB/s (+18.9% vs hist avg 1209.5 MB/s; min 225 / max 1808 over 27 PRs)

🔝 Throughputs per operation (vs. historical average)
Metric Current (MB/s) Cur Avg Δ% Hist avg Hist min Hist max
Read peak mean 6723 -6.8% 7212.7 5963 9526
Read avg mean 3900 -6.5% 4170.8 3524 5393
Read avg max 4322 -6.1% 4602.7 3812 5932
Write peak mean 1438 +18.9% 1209.5 225 1808
Write avg mean 457 +12.8% 405.3 91 546
Write avg max 809 +11.2% 727.8 224 956
Copy peak mean 2572 -4.0% 2680.1 2294 3489
Copy avg mean 1510 -4.8% 1587.0 1360 2251
Copy avg max 1639 -5.7% 1737.2 1515 2448
ServerCopy peak mean 3398 -8.8% 3726.5 3055 5090
ServerCopy avg mean 1776 -9.0% 1951.3 1604 2700
ServerCopy avg max 1828 -9.8% 2025.9 1675 2773

⏱️ Lantest (AFP 3.4) - LatencyGraph

Lantest latency

Avg total runtime: 4365 ms (+1.2% vs hist avg 4314.0 ms; min 2416 / max 5208 over 27 PRs)
Avg time per AFP op: 88 µs (+1.7% vs hist avg 86.5 µs; min 49 / max 105 over 27 PRs)

🐢 All operations (avg runtime, in test order, vs. historical average)
Metric Current (ms) Cur Avg Δ% Adj Δ% Hist avg Hist min Hist max
Writing one large file 38 +4.0% 36.6 26 41
Reading one large file 14 -7.6% 15.1 12 18
Creating 2000 files 489 -5.9% -14.4% 519.5 255 831
Create 2000 dirs tree (20×9×10) 485 -5.9% -14.5% 515.6 300 796
Open, write 1024 bytes, close 2000 files 410 +9.2% +0.6% 375.6 223 459
Open, read 1024 bytes, close 2000 files 357 +8.5% +0.0% 329.0 204 408
Copying 1000 files client-side (R+W) 578 +2.6% -5.9% 563.3 305 677
Copying 2000 files server-side 484 -8.2% -16.7% 527.3 217 727
Stat (lookup+getparams) 2000 files 250 +11.8% +3.3% 223.6 141 282
Enumerate dir with 2000 files 11 +28.0% +19.5% 8.59 3 14
Lock then unlock 2000 open forks 187 +14.2% +5.7% 163.7 118 199
Deleting 2000 files 332 -4.6% -13.1% 347.9 150 447
Byte-range lock/unlock 2000 ranges in one fork 178 +6.4% -2.1% 167.2 124 196
Directory cache hits (20 dirs x 100 files) 109 +9.8% +1.2% 99.3 67 122
Mixed cache operations (create/stat/enum/delete) on 500 files 218 -0.8% -9.4% 219.9 106 265
Deep path traversal (20 levels x 100 walks) 115 +8.6% +0.1% 105.9 67 131
Cache validation (500 files x 4 lookups) 110 +14.8% +6.2% 95.9 66 116

Run baseline: median op-test delta +8.5%, MAD 5.9%. Adj Δ% shifts each delta by the median; standouts ≥5% in bold. A large MAD means the run did not move uniformly — read the adjusted column with caution.

Performance trend

@andylemin
andylemin merged commit d0156d6 into main Aug 26, 2026
71 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants