feat(store): scan orphan workspaces on startup
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
79581e9824
commit
a2067baa5a
2 changed files with 37 additions and 14 deletions
6
store.go
6
store.go
|
|
@ -128,6 +128,8 @@ func WithPurgeInterval(interval time.Duration) StoreOption {
|
|||
}
|
||||
|
||||
// Usage example: `storeInstance, err := store.NewConfigured(store.StoreConfig{DatabasePath: ":memory:", Journal: store.JournalConfiguration{EndpointURL: "http://127.0.0.1:8086", Organisation: "core", BucketName: "events"}, PurgeInterval: 20 * time.Millisecond})`
|
||||
// NewConfigured also scans `.core/state` for leftover `.duckdb` workspace files
|
||||
// so orphan recovery can happen before the first explicit recovery call.
|
||||
func NewConfigured(config StoreConfig) (*Store, error) {
|
||||
storeInstance, err := openStore("store.NewConfigured", config.DatabasePath)
|
||||
if err != nil {
|
||||
|
|
@ -145,11 +147,14 @@ func NewConfigured(config StoreConfig) (*Store, error) {
|
|||
storeInstance.purgeInterval = config.PurgeInterval
|
||||
}
|
||||
|
||||
_ = discoverOrphanWorkspacePaths(defaultWorkspaceStateDirectory)
|
||||
storeInstance.startBackgroundPurge()
|
||||
return storeInstance, nil
|
||||
}
|
||||
|
||||
// Usage example: `storeInstance, err := store.New("/tmp/go-store.db", store.WithJournal("http://127.0.0.1:8086", "core", "events"))`
|
||||
// New scans `.core/state` for leftover `.duckdb` workspace files before the
|
||||
// store starts its background purge loop.
|
||||
func New(databasePath string, options ...StoreOption) (*Store, error) {
|
||||
storeInstance, err := openStore("store.New", databasePath)
|
||||
if err != nil {
|
||||
|
|
@ -160,6 +165,7 @@ func New(databasePath string, options ...StoreOption) (*Store, error) {
|
|||
option(storeInstance)
|
||||
}
|
||||
}
|
||||
_ = discoverOrphanWorkspacePaths(defaultWorkspaceStateDirectory)
|
||||
storeInstance.startBackgroundPurge()
|
||||
return storeInstance, nil
|
||||
}
|
||||
|
|
|
|||
45
workspace.go
45
workspace.go
|
|
@ -109,19 +109,13 @@ func (storeInstance *Store) NewWorkspace(name string) (*Workspace, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// RecoverOrphans(".core/state") returns orphaned workspaces such as
|
||||
// `scroll-session.duckdb` so callers can inspect Aggregate() and then Discard().
|
||||
// Usage example: `orphans := storeInstance.RecoverOrphans(".core/state")`
|
||||
func (storeInstance *Store) RecoverOrphans(stateDirectory string) []*Workspace {
|
||||
if storeInstance == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// discoverOrphanWorkspacePaths(".core/state") returns leftover workspace files
|
||||
// such as `scroll-session.duckdb` without opening them.
|
||||
func discoverOrphanWorkspacePaths(stateDirectory string) []string {
|
||||
filesystem := (&core.Fs{}).NewUnrestricted()
|
||||
if stateDirectory == "" {
|
||||
stateDirectory = defaultWorkspaceStateDirectory
|
||||
}
|
||||
|
||||
filesystem := (&core.Fs{}).NewUnrestricted()
|
||||
if !filesystem.Exists(stateDirectory) {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -147,19 +141,42 @@ func (storeInstance *Store) RecoverOrphans(stateDirectory string) []*Workspace {
|
|||
}
|
||||
})
|
||||
|
||||
var orphanWorkspaces []*Workspace
|
||||
orphanPaths := make([]string, 0, len(directoryEntries))
|
||||
for _, dirEntry := range directoryEntries {
|
||||
if dirEntry.IsDir() || !core.HasSuffix(dirEntry.Name(), ".duckdb") {
|
||||
continue
|
||||
}
|
||||
name := core.TrimSuffix(dirEntry.Name(), ".duckdb")
|
||||
databasePath := workspaceFilePath(stateDirectory, name)
|
||||
orphanPaths = append(orphanPaths, workspaceFilePath(stateDirectory, core.TrimSuffix(dirEntry.Name(), ".duckdb")))
|
||||
}
|
||||
return orphanPaths
|
||||
}
|
||||
|
||||
func workspaceNameFromPath(stateDirectory, databasePath string) string {
|
||||
relativePath := core.TrimPrefix(databasePath, joinPath(stateDirectory, ""))
|
||||
return core.TrimSuffix(relativePath, ".duckdb")
|
||||
}
|
||||
|
||||
// RecoverOrphans(".core/state") returns orphaned workspaces such as
|
||||
// `scroll-session.duckdb` so callers can inspect Aggregate() and then Discard().
|
||||
// Usage example: `orphans := storeInstance.RecoverOrphans(".core/state")`
|
||||
func (storeInstance *Store) RecoverOrphans(stateDirectory string) []*Workspace {
|
||||
if storeInstance == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if stateDirectory == "" {
|
||||
stateDirectory = defaultWorkspaceStateDirectory
|
||||
}
|
||||
|
||||
filesystem := (&core.Fs{}).NewUnrestricted()
|
||||
var orphanWorkspaces []*Workspace
|
||||
for _, databasePath := range discoverOrphanWorkspacePaths(stateDirectory) {
|
||||
workspaceDatabase, err := openWorkspaceDatabase(databasePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
orphanWorkspaces = append(orphanWorkspaces, &Workspace{
|
||||
name: name,
|
||||
name: workspaceNameFromPath(stateDirectory, databasePath),
|
||||
backingStore: storeInstance,
|
||||
database: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue