Automatic instance cleanup#1007
Merged
Merged
Conversation
The per run cleanup only sees instances that still have a data directory under the data root. Once that directory is gone, cleared with the temp directory or by the cleanup itself, nothing points at the instance and the system databases, logs and traces LocalDB keeps for it are never reclaimed. On top of that, deleting an instance leaves its logs and event files behind as an abandoned directory. Both accumulate indefinitely. The directory LocalDB keeps for each instance is now swept at startup: - A directory with no registered instance behind it is residue from an already deleted instance and is removed. - A registered instance with no data directory, and not running, is an orphan and is stopped, deleted, and its directory removed. Only directories untouched for InstanceCleanupThreshold, defaulting to 30 days, are processed. This keeps the startup scan cheap and avoids racing an instance being created or in use. Configurable via the LocalDBInstanceCleanupDays environment variable; zero disables it. Attribution is by state, not authorship: residue has no live instance so it is safe to remove whatever created it, and only instances with no data directory are treated as orphans, so an instance in active use is left alone. The default instances LocalDB manages itself are always skipped. The test suite sets the threshold to zero in its module initializer, so running the tests does not sweep the real instance root as a side effect.
A first run against a large backlog would otherwise stop and delete every orphaned instance and remove every residue directory in one startup, which is disk bound and adds a noticeable delay to that run. At most InstanceCleanupLimit removals happen per run, defaulting to 20, so the backlog drains over several runs. Skips are cheap and do not count against the limit, so recently touched or in use directories never crowd out the stale ones. Configurable via the LocalDBInstanceCleanupLimit environment variable; zero removes the limit. DeleteOrphanInstances remains the way to reclaim everything at once.
LocalDB instances are shared by everything on the machine that uses LocalDB, and nothing in an instance records what created it. Reclaiming one therefore meant guessing, and the sweep could remove an instance belonging to something else entirely. A marker file is now written into the directory LocalDB keeps for each instance this library starts, and the ongoing sweep only reclaims marked instances. Marking on start as well as on create means instances that predate marking are picked up the next time they are used. Marking is best effort: an instance that cannot be marked is simply never reclaimed automatically. Instances that predate marking cannot be told apart from instances belonging to anything else, so they get a single best effort pass, recorded under %LocalAppData%\LocalDb so it happens once per machine. That pass removes directories left behind by already deleted instances, which have no instance to harm, and orphans that still carry the shrunk model.mdf this library leaves behind. Nothing else is touched, so it can never remove a foreign instance. The pass is only recorded as done when the sweep actually ran, so a sweep that could not start does not consume the one chance the backlog gets. This replaces the per run cap. The ongoing sweep now only ever considers instances known to be ours, which is a much smaller set.
The only instances DeleteOrphanInstances reclaimed that the automatic sweep does not are the unmarked ones that carry no sign of having been created here. Removing those is exactly what the marker exists to prevent, so the API contradicted the model it now sits behind. It was also never able to clean up after itself: it enumerated registered instances, so directories left behind by already deleted instances were invisible to it, and those are the bulk of what accumulates. Anything the one time pass deliberately leaves is now left for SqlLocalDB.exe delete. Residue gets a short threshold of its own rather than the instance threshold. It has no instance to race, only the window where LocalDB has created the directory but not yet registered the instance, and the full threshold would strand any residue not yet old enough when the backlog pass runs, since that pass only happens once. IsDefaultInstance moves to DirectoryCleaner, its only remaining caller.
The readme described the data root cleanup as stopping a running instance before deleting its files. It has stopped, deleted, and removed the directory LocalDB keeps for the instance since that cleanup was changed, so both the prose and the flowchart node understated what it does. The sweep of the directory LocalDB keeps for each instance was not documented at all, though it is where the growth being reclaimed actually accumulates. Adds a flowchart for the decision it makes per directory: whether the directory is LocalDB managed, backed by a registered instance or only residue, marked as created here, still tracked by a data directory, and whether the one time backlog pass applies.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.