fix(store): cache orphan workspaces during startup
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
1b5f59ebc5
commit
1c92e47b24
3 changed files with 64 additions and 1 deletions
12
store.go
12
store.go
|
|
@ -78,6 +78,9 @@ type Store struct {
|
|||
watchersLock sync.RWMutex // protects watcher registration and dispatch
|
||||
callbacksLock sync.RWMutex // protects callback registration and dispatch
|
||||
nextCallbackRegistrationID uint64 // monotonic ID for callback registrations
|
||||
|
||||
orphanWorkspacesLock sync.Mutex
|
||||
orphanWorkspaces []*Workspace
|
||||
}
|
||||
|
||||
func (storeInstance *Store) ensureReady(operation string) error {
|
||||
|
|
@ -172,7 +175,7 @@ func openConfiguredStore(operation string, config StoreConfig) (*Store, error) {
|
|||
|
||||
// New() performs a non-destructive orphan scan so callers can discover
|
||||
// leftover workspaces via RecoverOrphans().
|
||||
discoverOrphanWorkspacePaths(defaultWorkspaceStateDirectory)
|
||||
storeInstance.orphanWorkspaces = discoverOrphanWorkspaces(defaultWorkspaceStateDirectory, storeInstance)
|
||||
storeInstance.startBackgroundPurge()
|
||||
return storeInstance, nil
|
||||
}
|
||||
|
|
@ -254,6 +257,13 @@ func (storeInstance *Store) Close() error {
|
|||
storeInstance.callbacks = nil
|
||||
storeInstance.callbacksLock.Unlock()
|
||||
|
||||
storeInstance.orphanWorkspacesLock.Lock()
|
||||
for _, orphanWorkspace := range storeInstance.orphanWorkspaces {
|
||||
orphanWorkspace.Discard()
|
||||
}
|
||||
storeInstance.orphanWorkspaces = nil
|
||||
storeInstance.orphanWorkspacesLock.Unlock()
|
||||
|
||||
if storeInstance.database == nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
29
workspace.go
29
workspace.go
|
|
@ -168,6 +168,25 @@ func discoverOrphanWorkspacePaths(stateDirectory string) []string {
|
|||
return orphanPaths
|
||||
}
|
||||
|
||||
func discoverOrphanWorkspaces(stateDirectory string, backingStore *Store) []*Workspace {
|
||||
filesystem := (&core.Fs{}).NewUnrestricted()
|
||||
orphanWorkspaces := make([]*Workspace, 0)
|
||||
for _, databasePath := range discoverOrphanWorkspacePaths(stateDirectory) {
|
||||
workspaceDatabase, err := openWorkspaceDatabase(databasePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
orphanWorkspaces = append(orphanWorkspaces, &Workspace{
|
||||
name: workspaceNameFromPath(stateDirectory, databasePath),
|
||||
backingStore: backingStore,
|
||||
database: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
filesystem: filesystem,
|
||||
})
|
||||
}
|
||||
return orphanWorkspaces
|
||||
}
|
||||
|
||||
func workspaceNameFromPath(stateDirectory, databasePath string) string {
|
||||
relativePath := core.TrimPrefix(databasePath, joinPath(stateDirectory, ""))
|
||||
return core.TrimSuffix(relativePath, ".duckdb")
|
||||
|
|
@ -185,6 +204,16 @@ func (storeInstance *Store) RecoverOrphans(stateDirectory string) []*Workspace {
|
|||
stateDirectory = defaultWorkspaceStateDirectory
|
||||
}
|
||||
|
||||
if stateDirectory == defaultWorkspaceStateDirectory {
|
||||
storeInstance.orphanWorkspacesLock.Lock()
|
||||
cachedWorkspaces := storeInstance.orphanWorkspaces
|
||||
storeInstance.orphanWorkspaces = nil
|
||||
storeInstance.orphanWorkspacesLock.Unlock()
|
||||
if len(cachedWorkspaces) > 0 {
|
||||
return cachedWorkspaces
|
||||
}
|
||||
}
|
||||
|
||||
filesystem := (&core.Fs{}).NewUnrestricted()
|
||||
var orphanWorkspaces []*Workspace
|
||||
for _, databasePath := range discoverOrphanWorkspacePaths(stateDirectory) {
|
||||
|
|
|
|||
|
|
@ -222,3 +222,27 @@ func TestWorkspace_New_Good_LeavesOrphanedWorkspacesForRecovery(t *testing.T) {
|
|||
assert.False(t, testFilesystem().Exists(orphanDatabasePath+"-wal"))
|
||||
assert.False(t, testFilesystem().Exists(orphanDatabasePath+"-shm"))
|
||||
}
|
||||
|
||||
func TestWorkspace_New_Good_CachesOrphansDuringConstruction(t *testing.T) {
|
||||
stateDirectory := useWorkspaceStateDirectory(t)
|
||||
requireCoreOK(t, testFilesystem().EnsureDir(stateDirectory))
|
||||
|
||||
orphanDatabasePath := workspaceFilePath(stateDirectory, "orphan-session")
|
||||
orphanDatabase, err := openWorkspaceDatabase(orphanDatabasePath)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, orphanDatabase.Close())
|
||||
assert.True(t, testFilesystem().Exists(orphanDatabasePath))
|
||||
|
||||
storeInstance, err := New(":memory:")
|
||||
require.NoError(t, err)
|
||||
defer storeInstance.Close()
|
||||
|
||||
requireCoreOK(t, testFilesystem().DeleteAll(stateDirectory))
|
||||
assert.False(t, testFilesystem().Exists(orphanDatabasePath))
|
||||
|
||||
orphans := storeInstance.RecoverOrphans(stateDirectory)
|
||||
require.Len(t, orphans, 1)
|
||||
assert.Equal(t, "orphan-session", orphans[0].Name())
|
||||
assert.Equal(t, map[string]any{}, orphans[0].Aggregate())
|
||||
orphans[0].Discard()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue