Files
VictoriaMetrics/lib/persistentqueue/persistentqueue_test.go

393 lines
11 KiB
Go
Raw Normal View History

package persistentqueue
import (
"fmt"
"os"
"path/filepath"
"strconv"
"testing"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
)
func TestQueueOpenClose(t *testing.T) {
path := "queue-open-close"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
for range 3 {
q := mustOpen(path, "foobar", 0)
if n := q.GetPendingBytes(); n > 0 {
t.Fatalf("pending bytes must be 0; got %d", n)
}
q.MustClose()
}
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
}
func TestQueueOpen(t *testing.T) {
t.Run("invalid-metainfo", func(_ *testing.T) {
path := "queue-open-invalid-metainfo"
mustCreateDir(path)
mustCreateFile(filepath.Join(path, metainfoFilename), "foobarbaz")
q := mustOpen(path, "foobar", 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("junk-files-and-dirs", func(_ *testing.T) {
path := "queue-open-junk-files-and-dir"
mustCreateDir(path)
mustCreateEmptyMetainfo(path, "foobar")
mustCreateFile(filepath.Join(path, "junk-file"), "foobar")
mustCreateDir(filepath.Join(path, "junk-dir"))
q := mustOpen(path, "foobar", 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("invalid-chunk-offset", func(_ *testing.T) {
path := "queue-open-invalid-chunk-offset"
mustCreateDir(path)
mustCreateEmptyMetainfo(path, "foobar")
mustCreateFile(filepath.Join(path, fmt.Sprintf("%016X", 1234)), "qwere")
q := mustOpen(path, "foobar", 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("too-new-chunk", func(_ *testing.T) {
path := "queue-open-too-new-chunk"
mustCreateDir(path)
mustCreateEmptyMetainfo(path, "foobar")
mustCreateFile(filepath.Join(path, fmt.Sprintf("%016X", 100*uint64(DefaultChunkFileSize))), "asdf")
q := mustOpen(path, "foobar", 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("too-old-chunk", func(t *testing.T) {
path := "queue-open-too-old-chunk"
mustCreateDir(path)
mi := &metainfo{
Name: "foobar",
ReaderOffset: DefaultChunkFileSize,
WriterOffset: DefaultChunkFileSize,
}
if err := mi.WriteToFile(filepath.Join(path, metainfoFilename)); err != nil {
t.Fatalf("unexpected error: %s", err)
}
mustCreateFile(filepath.Join(path, fmt.Sprintf("%016X", 0)), "adfsfd")
q := mustOpen(path, mi.Name, 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("too-big-reader-offset", func(t *testing.T) {
path := "queue-open-too-big-reader-offset"
mustCreateDir(path)
mi := &metainfo{
Name: "foobar",
ReaderOffset: DefaultChunkFileSize + 123,
}
if err := mi.WriteToFile(filepath.Join(path, metainfoFilename)); err != nil {
t.Fatalf("unexpected error: %s", err)
}
q := mustOpen(path, mi.Name, 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("metainfo-dir", func(_ *testing.T) {
path := "queue-open-metainfo-dir"
mustCreateDir(path)
mustCreateDir(filepath.Join(path, metainfoFilename))
q := mustOpen(path, "foobar", 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("too-small-reader-file", func(t *testing.T) {
path := "too-small-reader-file"
mustCreateDir(path)
mi := &metainfo{
Name: "foobar",
ReaderOffset: 123,
WriterOffset: 123,
}
if err := mi.WriteToFile(filepath.Join(path, metainfoFilename)); err != nil {
t.Fatalf("unexpected error: %s", err)
}
mustCreateFile(filepath.Join(path, fmt.Sprintf("%016X", 0)), "sdf")
q := mustOpen(path, mi.Name, 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("invalid-writer-file-size", func(_ *testing.T) {
path := "too-small-reader-file"
mustCreateDir(path)
mustCreateEmptyMetainfo(path, "foobar")
mustCreateFile(filepath.Join(path, fmt.Sprintf("%016X", 0)), "sdfdsf")
q := mustOpen(path, "foobar", 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
t.Run("invalid-queue-name", func(t *testing.T) {
path := "invalid-queue-name"
mustCreateDir(path)
mi := &metainfo{
Name: "foobar",
}
if err := mi.WriteToFile(filepath.Join(path, metainfoFilename)); err != nil {
t.Fatalf("unexpected error: %s", err)
}
mustCreateFile(filepath.Join(path, fmt.Sprintf("%016X", 0)), "sdf")
q := mustOpen(path, "baz", 0)
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
})
}
func TestQueueResetIfEmpty(t *testing.T) {
path := "queue-reset-if-empty"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
q := mustOpen(path, "foobar", 0)
defer func() {
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
}()
block := make([]byte, 1024*1024)
var buf []byte
for range 10 {
for range 10 {
q.MustWriteBlock(block)
var ok bool
buf, ok = q.MustReadBlockNonblocking(buf[:0])
if !ok {
t.Fatalf("unexpected ok=false returned from MustReadBlockNonblocking")
}
}
q.ResetIfEmpty()
if n := q.GetPendingBytes(); n > 0 {
t.Fatalf("unexpected non-zero pending bytes after queue reset: %d", n)
}
q.ResetIfEmpty()
if n := q.GetPendingBytes(); n > 0 {
t.Fatalf("unexpected non-zero pending bytes after queue reset: %d", n)
}
}
}
func TestQueueWriteRead(t *testing.T) {
path := "queue-write-read"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
q := mustOpen(path, "foobar", 0)
defer func() {
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
}()
for j := range 5 {
var blocks [][]byte
for i := range 10 {
2026-02-18 18:21:02 +01:00
block := fmt.Appendf(nil, "block %d+%d", j, i)
q.MustWriteBlock(block)
blocks = append(blocks, block)
}
if n := q.GetPendingBytes(); n <= 0 {
t.Fatalf("pending bytes must be greater than 0; got %d", n)
}
var buf []byte
var ok bool
for _, block := range blocks {
buf, ok = q.MustReadBlockNonblocking(buf[:0])
if !ok {
t.Fatalf("unexpected ok=%v returned from MustReadBlockNonblocking; want true", ok)
}
if string(buf) != string(block) {
t.Fatalf("unexpected block read; got %q; want %q", buf, block)
}
}
if n := q.GetPendingBytes(); n > 0 {
t.Fatalf("pending bytes must be 0; got %d", n)
}
}
}
func TestQueueWriteCloseRead(t *testing.T) {
path := "queue-write-close-read"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
q := mustOpen(path, "foobar", 0)
defer func() {
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
}()
for j := range 5 {
var blocks [][]byte
for i := range 10 {
2026-02-18 18:21:02 +01:00
block := fmt.Appendf(nil, "block %d+%d", j, i)
q.MustWriteBlock(block)
blocks = append(blocks, block)
}
if n := q.GetPendingBytes(); n <= 0 {
t.Fatalf("pending bytes must be greater than 0; got %d", n)
}
q.MustClose()
q = mustOpen(path, "foobar", 0)
if n := q.GetPendingBytes(); n <= 0 {
t.Fatalf("pending bytes must be greater than 0; got %d", n)
}
var buf []byte
var ok bool
for _, block := range blocks {
buf, ok = q.MustReadBlockNonblocking(buf[:0])
if !ok {
t.Fatalf("unexpected ok=%v returned from MustReadBlockNonblocking; want true", ok)
}
if string(buf) != string(block) {
t.Fatalf("unexpected block read; got %q; want %q", buf, block)
}
}
if n := q.GetPendingBytes(); n > 0 {
t.Fatalf("pending bytes must be 0; got %d", n)
}
}
}
func TestQueueChunkManagementSimple(t *testing.T) {
path := "queue-chunk-management-simple"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
const chunkFileSize = 100
const maxBlockSize = 20
q := mustOpenInternal(path, "foobar", chunkFileSize, maxBlockSize, 0)
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
defer fs.MustRemoveDir(path)
defer q.MustClose()
var blocks []string
for i := range 100 {
block := fmt.Sprintf("block %d", i)
q.MustWriteBlock([]byte(block))
blocks = append(blocks, block)
}
if n := q.GetPendingBytes(); n == 0 {
t.Fatalf("unexpected zero number of bytes pending")
}
for _, block := range blocks {
data, ok := q.MustReadBlockNonblocking(nil)
if !ok {
t.Fatalf("unexpected ok=false")
}
if block != string(data) {
t.Fatalf("unexpected block read; got %q; want %q", data, block)
}
}
if n := q.GetPendingBytes(); n != 0 {
t.Fatalf("unexpected non-zero number of pending bytes: %d", n)
}
}
func TestQueueChunkManagementPeriodicClose(t *testing.T) {
path := "queue-chunk-management-periodic-close"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
const chunkFileSize = 100
const maxBlockSize = 20
q := mustOpenInternal(path, "foobar", chunkFileSize, maxBlockSize, 0)
defer func() {
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
}()
var blocks []string
for i := range 100 {
block := fmt.Sprintf("block %d", i)
q.MustWriteBlock([]byte(block))
blocks = append(blocks, block)
q.MustClose()
q = mustOpenInternal(path, "foobar", chunkFileSize, maxBlockSize, 0)
}
if n := q.GetPendingBytes(); n == 0 {
t.Fatalf("unexpected zero number of bytes pending")
}
for _, block := range blocks {
data, ok := q.MustReadBlockNonblocking(nil)
if !ok {
t.Fatalf("unexpected ok=false")
}
if block != string(data) {
t.Fatalf("unexpected block read; got %q; want %q", data, block)
}
q.MustClose()
q = mustOpenInternal(path, "foobar", chunkFileSize, maxBlockSize, 0)
}
if n := q.GetPendingBytes(); n != 0 {
t.Fatalf("unexpected non-zero number of pending bytes: %d", n)
}
}
func TestQueueLimitedSize(t *testing.T) {
const maxPendingBytes = 1000
path := "queue-limited-size"
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
q := mustOpen(path, "foobar", maxPendingBytes)
defer func() {
q.MustClose()
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
}()
// Check that small blocks are successfully buffered and read
var blocks []string
for i := range 10 {
block := fmt.Sprintf("block_%d", i)
q.MustWriteBlock([]byte(block))
blocks = append(blocks, block)
}
var buf []byte
var ok bool
for _, block := range blocks {
buf, ok = q.MustReadBlockNonblocking(buf[:0])
if !ok {
t.Fatalf("unexpected ok=false")
}
if string(buf) != block {
t.Fatalf("unexpected block read; got %q; want %q", buf, block)
}
}
// Make sure that old blocks are dropped on queue size overflow
for i := range maxPendingBytes {
block := fmt.Sprintf("%d", i)
q.MustWriteBlock([]byte(block))
}
if n := q.GetPendingBytes(); n > maxPendingBytes {
t.Fatalf("too many pending bytes; got %d; mustn't exceed %d", n, maxPendingBytes)
}
buf, ok = q.MustReadBlockNonblocking(buf[:0])
if !ok {
t.Fatalf("unexpected ok=false")
}
blockNum, err := strconv.Atoi(string(buf))
if err != nil {
t.Fatalf("cannot parse block contents: %s", err)
}
if blockNum < 20 {
t.Fatalf("too small block number: %d; it looks like it wasn't dropped", blockNum)
}
// Try writing a block with too big size
block := make([]byte, maxPendingBytes+1)
q.MustWriteBlock(block)
if n := q.GetPendingBytes(); n != 0 {
t.Fatalf("unexpected non-empty queue after writing a block with too big size; queue size: %d bytes", n)
}
}
func mustCreateFile(path, contents string) {
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustWriteSync(path, []byte(contents))
}
func mustCreateDir(path string) {
lib/fs: simplify the code for directory removal and make it compatible with object storage (S3) and NFS - Drop the code needed for asynchronous removal of the directory on NFS shares. This code was needed when VictoriaMetrics could keep open files after their deletion or renaming. This is no longer the case after the commit 43b24164efdd35c2641a289ab93f5cb94279cb60 . Now files are deleted only after all the readers close them. This updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 - Unify MustRemoveAll() and MustRemoveDirAtomic() into MustRemoveDir() and MustRemovePath() functions: - The MustRemoveDir() deletes the given directory with all its contents, in an "atomic" way: it creates a special `.delete-this-dir` file in the directory, then removes all its contents except of this file, and later removes the `.delete-this-dir` file together with the directory itself. This makes possible easily determining whether the given directory needs to be deleted after unclean shutdown - if it contains the `.delete-this-dir` file or if it is empty, it must be deleted. Add IsPartiallyRemovedDir() function, which can be used for detecting whether the given directory must be removed at starup. Previously the MustRemoveDirAtomic() was using a "trick" for atomic directory removal: it was "atomically" renaming the directory to a temporary directory with '.must-remove.' marker in the directory name, and after that it was removing the renamed directory. On startup all the directories with the `.must-remove.` marker were deleted if they are left after unclean shutdown. This "trick" doesn't work for NFS and object storage such as S3, since these storage systems do not support atomic renaming of directories with multiple entries inside. The new MustRemoveDir() function doesn't use this "trick", so it can be safely used in NFS and S3-like storage systems. This is based on the pull request from @func25 - https://github.com/VictoriaMetrics/VictoriaMetrics/pull/9486/files . - The MustRemovePath() deletes the given file or an empty directory. - Delete the existing parts and partitions at startup if they were partially deleted. - Consistently use fs.MustRemoveDir() and fs.MustRemovePath() instead of os.RemoveAll() across the codebase. This reduces the amounts of bolierplate code related to error handling. - Consistently use fs.MustWriteSync() instead of os.WriteFile() across the codebase.
2025-07-25 18:41:17 +02:00
fs.MustRemoveDir(path)
if err := os.MkdirAll(path, 0700); err != nil {
panic(fmt.Errorf("cannot create dir %q: %w", path, err))
}
}
func mustCreateEmptyMetainfo(path, name string) {
var mi metainfo
mi.Name = name
if err := mi.WriteToFile(filepath.Join(path, metainfoFilename)); err != nil {
panic(fmt.Errorf("cannot create metainfo: %w", err))
}
}