Add read-only mode for extension aware workspace filer (#1609)

## Changes

By default, construct a read/write instance. If constructed in read-only
mode, the underlying filer is wrapped in a readahead cache.

## Tests

* Filer integration tests pass.
* Manual test that caching is enabled when running on WSFS.
This commit is contained in:
Pieter Noordhuis 2024-07-18 16:17:42 +02:00 committed by GitHub
parent 5b65358146
commit 6953a5d5af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 40 additions and 6 deletions

View File

@ -39,7 +39,7 @@ func (m *configureWSFS) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagno
// If so, swap out vfs.Path instance of the sync root with one that
// makes all Workspace File System interactions extension aware.
p, err := vfs.NewFilerPath(ctx, root, func(path string) (filer.Filer, error) {
return filer.NewWorkspaceFilesExtensionsClient(b.WorkspaceClient(), path)
return filer.NewReadOnlyWorkspaceFilesExtensionsClient(b.WorkspaceClient(), path)
})
if err != nil {
return diag.FromErr(err)

View File

@ -20,6 +20,7 @@ type workspaceFilesExtensionsClient struct {
wsfs Filer
root string
readonly bool
}
var extensionsToLanguages = map[string]workspace.Language{
@ -143,6 +144,14 @@ func (e DuplicatePathError) Error() string {
return fmt.Sprintf("failed to read files from the workspace file system. Duplicate paths encountered. Both %s at %s and %s at %s resolve to the same name %s. Changing the name of one of these objects will resolve this issue", e.oi1.ObjectType, e.oi1.Path, e.oi2.ObjectType, e.oi2.Path, e.commonName)
}
type ReadOnlyError struct {
op string
}
func (e ReadOnlyError) Error() string {
return fmt.Sprintf("failed to %s: filer is in read-only mode", e.op)
}
// This is a filer for the workspace file system that allows you to pretend the
// workspace file system is a traditional file system. It allows you to list, read, write,
// delete, and stat notebooks (and files in general) in the workspace, using their paths
@ -157,17 +166,30 @@ func (e DuplicatePathError) Error() string {
// errors for namespace clashes (e.g. a file and a notebook or a directory and a notebook).
// Thus users of these methods should be careful to avoid such clashes.
func NewWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
return newWorkspaceFilesExtensionsClient(w, root, false)
}
func NewReadOnlyWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
return newWorkspaceFilesExtensionsClient(w, root, true)
}
func newWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string, readonly bool) (Filer, error) {
filer, err := NewWorkspaceFilesClient(w, root)
if err != nil {
return nil, err
}
cache := newWorkspaceFilesReadaheadCache(filer)
if readonly {
// Wrap in a readahead cache to avoid making unnecessary calls to the workspace.
filer = newWorkspaceFilesReadaheadCache(filer)
}
return &workspaceFilesExtensionsClient{
workspaceClient: w,
wsfs: cache,
wsfs: filer,
root: root,
readonly: readonly,
}, nil
}
@ -214,6 +236,10 @@ func (w *workspaceFilesExtensionsClient) ReadDir(ctx context.Context, name strin
// (e.g. a file and a notebook or a directory and a notebook). Thus users of this
// method should be careful to avoid such clashes.
func (w *workspaceFilesExtensionsClient) Write(ctx context.Context, name string, reader io.Reader, mode ...WriteMode) error {
if w.readonly {
return ReadOnlyError{"write"}
}
return w.wsfs.Write(ctx, name, reader, mode...)
}
@ -247,6 +273,10 @@ func (w *workspaceFilesExtensionsClient) Read(ctx context.Context, name string)
// Try to delete the file as a regular file. If the file is not found, try to delete it as a notebook.
func (w *workspaceFilesExtensionsClient) Delete(ctx context.Context, name string, mode ...DeleteMode) error {
if w.readonly {
return ReadOnlyError{"delete"}
}
err := w.wsfs.Delete(ctx, name, mode...)
// If the file is not found, it might be a notebook.
@ -293,5 +323,9 @@ func (w *workspaceFilesExtensionsClient) Stat(ctx context.Context, name string)
// (e.g. a file and a notebook or a directory and a notebook). Thus users of this
// method should be careful to avoid such clashes.
func (w *workspaceFilesExtensionsClient) Mkdir(ctx context.Context, name string) error {
if w.readonly {
return ReadOnlyError{"mkdir"}
}
return w.wsfs.Mkdir(ctx, name)
}