Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vfs: MemFS Link erroneously shares refcount #2064

Closed
tbg opened this issue Oct 27, 2022 · 0 comments · Fixed by #2065
Closed

vfs: MemFS Link erroneously shares refcount #2064

tbg opened this issue Oct 27, 2022 · 0 comments · Fixed by #2065
Labels
A-storage C-bug Something isn't working T-storage

Comments

@tbg
Copy link
Member

tbg commented Oct 27, 2022

vfs.Link1 reuses the same *memNode for the old and new location. In particular, this means that its refs field2 is now shared. This means that a hardlinked file cannot be deleted if the original is currently open (or vice versa):

func TestFoo(t *testing.T) {
	fs := vfs.NewMem()
	{
		// Write SST somewhere.
		f, err := fs.Create("file.txt")
		require.NoError(t, err)
		_, err = f.Write([]byte("hi"))
		require.NoError(t, err)
		require.NoError(t, f.Close())
	}
	// Ingest SST into LSM.
	require.NoError(t, fs.Link("file.txt", "file2.txt"))
	// Pebble does something with the SST, like compact it. Won't close it until test ends.
	{
		f, err := fs.Open("file2.txt")
		require.NoError(t, err)
		defer func() {
			require.NoError(t, f.Close())
		}()
	}

	// Try to remove original file.
	require.NoError(t, fs.Remove("file.txt")) // <-- will fail: "invalid argument"
}

We should not share the atomic. The hard-link should get its own atomic counter.

When this is fixed, this work-around can probably be removed:

pebble/ingest.go

Lines 282 to 298 in 5a2941f

if _, ok := opts.FS.(*vfs.MemFS); ok && opts.DebugCheck != nil {
// The combination of MemFS+Ingest+DebugCheck produces awkwardness around
// the subsequent deletion of files. The problem is that MemFS implements
// the Windows semantics of disallowing removal of an open file. This is
// desirable because it helps catch bugs where we violate the
// requirements of the Windows semantics. The normal practice for Ingest
// is for the caller to remove the source files after the ingest
// completes successfully. Unfortunately, Options.DebugCheck causes
// ingest to run DB.CheckLevels() before the ingest finishes, and
// DB.CheckLevels() populates the table cache with the newly ingested
// files.
//
// The combination of MemFS+Ingest+DebugCheck is primarily used in
// tests. As a workaround, disable hard linking this combination
// occurs. See https://github.com/cockroachdb/pebble/issues/495.
err = vfs.Copy(fs, paths[i], target)
} else {

Found while investigating a CRDB log truncation test3.

See also #1236

Footnotes

  1. https://github.com/cockroachdb/pebble/blob/b82ab1300c3a5320a68b1607df271d310b737086/vfs/mem_fs.go#L208-L248

  2. https://github.com/cockroachdb/pebble/blob/b82ab1300c3a5320a68b1607df271d310b737086/vfs/mem_fs.go#L498

  3. https://github.com/cockroachdb/cockroach/pull/89632#issuecomment-1293415352

@tbg tbg added C-bug Something isn't working T-storage labels Oct 27, 2022
jbowens added a commit to jbowens/pebble that referenced this issue Oct 27, 2022
Default to Unix semantics in MemFS. The Windows semantics are left as
configurable for unit tests that seek to ensure we don't remove open
files, when possible.

There are existing cases where we cannot satisfy Windows semantics, and
Go does not support opening files with the appropriate
`FILE_SHARE_DELETE` permission bit (see golang/go#34681,
golang/go#32088). The MemFS's implementation of Windows semantics is
useful for ensuring we don't regress in the cases where we can satisfy
Windows semantics.

Close cockroachdb#2064.
Informs cockroachdb#1236.
jbowens added a commit that referenced this issue Oct 27, 2022
Default to Unix semantics in MemFS. The Windows semantics are left as
configurable for unit tests that seek to ensure we don't remove open
files, when possible.

There are existing cases where we cannot satisfy Windows semantics, and
Go does not support opening files with the appropriate
`FILE_SHARE_DELETE` permission bit (see golang/go#34681,
golang/go#32088). The MemFS's implementation of Windows semantics is
useful for ensuring we don't regress in the cases where we can satisfy
Windows semantics.

Close #2064.
Informs #1236.
jbowens added a commit to jbowens/pebble that referenced this issue Oct 16, 2023
Default to Unix semantics in MemFS. The Windows semantics are left as
configurable for unit tests that seek to ensure we don't remove open
files, when possible.

There are existing cases where we cannot satisfy Windows semantics, and
Go does not support opening files with the appropriate
`FILE_SHARE_DELETE` permission bit (see golang/go#34681,
golang/go#32088). The MemFS's implementation of Windows semantics is
useful for ensuring we don't regress in the cases where we can satisfy
Windows semantics.

Close cockroachdb#2064.
Informs cockroachdb#1236.
jbowens added a commit that referenced this issue Oct 17, 2023
Default to Unix semantics in MemFS. The Windows semantics are left as
configurable for unit tests that seek to ensure we don't remove open
files, when possible.

There are existing cases where we cannot satisfy Windows semantics, and
Go does not support opening files with the appropriate
`FILE_SHARE_DELETE` permission bit (see golang/go#34681,
golang/go#32088). The MemFS's implementation of Windows semantics is
useful for ensuring we don't regress in the cases where we can satisfy
Windows semantics.

Close #2064.
Informs #1236.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-storage C-bug Something isn't working T-storage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant