<div dir="ltr">Hello,<div><br></div><div>I've recently been using journalctl on one of my longer-lived systems, and I'm running into a slight annoyance. Most of the time I'm using `journalctl -u <<unit>> -e`. I use tab completion for the unit name, and the annoyance is the long pause journalctl takes to complete a unit. With cold cache (meaning writing 3 to /proc/sys/vm/drop_caches), this takes 23 seconds on a system using Btrfs on a SATA3 SSD. With warm cache, it still takes 3-4 seconds. Both cases are quite a bit slower than normal tab completion behavior.</div><div><br></div><div>I'm wondering if there has been any discussion or examination on optimizing the bash completion to speed it up. </div><div><br></div><div>The Bash completion support for journalctl calls `journalctl -F '_SYSTEMD_UNIT'` to assemble a list of acceptable units. That leads to get_possible_units() in src/journal/journalctl.c, which calls the macro SD_JOURNAL_FOREACH_UNIQUE and then sd_journal_enumerate_unique() in sr/journal/sd-journal.c. </div><div><br></div><div>The problem from the user's perspective is that this scans through all the journals, including user journals, which in my case is 68. That leads me to a few possible optimization strategies, although each has downsides:</div><div><br></div><div>1) Instead of scanning through the journals for tab completion, use a more simplistic search that only uses "installed" units. By installed, I mean that tab completion only provides units that presently have a unit file on the system (/etc/systemd/system/, /lib/systemd/system/, etc.) regardless of enabled or activated state. Basically, just scan those directories for file names. </div><div><br></div><div>The obvious downside is that the user wouldn't be able to tab complete units which have since been deleted. </div><div><br></div><div>A simplistic POC solution would be to change L76-78 of shell-completion/bash/journalctl from</div><div><br></div><div><div>                        --unit|-u)</div><div>                                comps=$(journalctl -F '_SYSTEMD_UNIT' 2>/dev/null)</div><div>                        ;;</div></div><div><br></div><div>to something like</div><div><br></div><div><div>                        --unit|-u)</div><div>                                comps=$(ls /lib/systemd/system /etc/systemd/system | grep '\.service$\|\.timer$\|\.socket$')</div><div>                        ;;</div></div><div><br></div><div><br></div><div>2) Have the journal maintain an index of units, which have emitted log messages. That way tab completion would only need to scan this index to populate `journalctl -F '_SYSTEMD_UNIT'`. The index could either be read from disk or kept in memory.</div><div><br></div><div>The downside is two-fold. First, for every log message the journal would need to account for whether that unit is already in the index. If the index was constantly updated on disk, this adds an amount of addition IO. If it's in memory, the journal would consume additional runtime memory. Second, as old journals are removed due to cleaning, this index would need to be updated.</div><div><br></div><div>3) A combination of the two approaches. If this is even possible for shell completion, have the first tab completion attempt use method #1 or #2 and a second tab completion attempt use either #2 or the current behavior. The benefit is that a user using tab completion for convenience (instead of obtaining an exhaustive list of all units) and knows what she is looking for (eg. Network<<tab>> for NetworkManager.service) gets a fast answer.</div><div><br></div><div>The downside is whether shell completion can even handle multiple behaviors and causing user confusion by altering the user interface. </div><div><br></div><div>Thoughts?</div><div><br></div><div>Thanks,</div><div>Justin</div><div><br></div></div>