From f3a03c416408bf7d81dee438a10566428962c5ee Mon Sep 17 00:00:00 2001 From: Nikolay <nik@victoriametrics.com> Date: Sat, 27 Feb 2021 01:37:07 +0300 Subject: [PATCH 1/3] Adds windows build (#1040) * fixes windows compilation, adds signal impl for windows, adds free space usage for windows, https://github.com/VictoriaMetrics/VictoriaMetrics/issues/70 https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1036 NOTE victoria metrics database still CANNOT work under windows system, only vmagent is supported. To completly port victoria metrics, you have to fix issues with separators, parsing and posix file removall * rollback separator * Adds windows setInformation api, it must behave like unix, need to test it. changes procutil * check for invlaid param * Fixes posix delete semantic * refactored a bit * fixes openbsd build * removed windows api call * Fixes code after windows add * Update lib/procutil/signal_windows.go Co-authored-by: Aliaksandr Valialkin <valyala@gmail.com> --- app/vmagent/Makefile | 4 + lib/fs/fs.go | 42 +--------- lib/fs/fs_nix.go | 22 ++++- lib/fs/fs_openbsd.go | 18 ++++ lib/fs/fs_unix.go | 45 ++++++++++ lib/fs/fs_windows.go | 149 +++++++++++++++++++++++++++++++++ lib/fs/reader_at.go | 5 +- lib/procutil/signal.go | 2 + lib/procutil/signal_windows.go | 60 +++++++++++++ 9 files changed, 305 insertions(+), 42 deletions(-) create mode 100644 lib/fs/fs_unix.go create mode 100644 lib/fs/fs_windows.go create mode 100644 lib/procutil/signal_windows.go diff --git a/app/vmagent/Makefile b/app/vmagent/Makefile index 0ee29504d3..e0be998ab3 100644 --- a/app/vmagent/Makefile +++ b/app/vmagent/Makefile @@ -73,6 +73,10 @@ vmagent-ppc64le: vmagent-386: CGO_ENABLED=0 GOARCH=386 $(MAKE) vmagent-local-with-goarch +vmagent-windows: + GOOS=windows CGO_ENABLED=0 $(MAKE) vmagent-local-with-goarch + + vmagent-local-with-goarch: APP_NAME=vmagent $(MAKE) app-local-with-goarch diff --git a/lib/fs/fs.go b/lib/fs/fs.go index 229e0266bb..8f8c659434 100644 --- a/lib/fs/fs.go +++ b/lib/fs/fs.go @@ -13,26 +13,15 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime" "github.com/VictoriaMetrics/VictoriaMetrics/lib/filestream" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" - "golang.org/x/sys/unix" ) +var tmpFileNum uint64 + // MustSyncPath syncs contents of the given path. func MustSyncPath(path string) { - d, err := os.Open(path) - if err != nil { - logger.Panicf("FATAL: cannot open %q: %s", path, err) - } - if err := d.Sync(); err != nil { - _ = d.Close() - logger.Panicf("FATAL: cannot flush %q to storage: %s", path, err) - } - if err := d.Close(); err != nil { - logger.Panicf("FATAL: cannot close %q: %s", path, err) - } + mustSyncPath(path) } -var tmpFileNum uint64 - // WriteFileAtomically atomically writes data to the given file path. // // WriteFileAtomically returns only after the file is fully written and synced @@ -332,15 +321,7 @@ func MustWriteData(w io.Writer, data []byte) { // CreateFlockFile creates flock.lock file in the directory dir // and returns the handler to the file. func CreateFlockFile(dir string) (*os.File, error) { - flockFile := dir + "/flock.lock" - flockF, err := os.Create(flockFile) - if err != nil { - return nil, fmt.Errorf("cannot create lock file %q: %w", flockFile, err) - } - if err := unix.Flock(int(flockF.Fd()), unix.LOCK_EX|unix.LOCK_NB); err != nil { - return nil, fmt.Errorf("cannot acquire lock on file %q: %w", flockFile, err) - } - return flockF, nil + return createFlockFile(dir) } // MustGetFreeSpace returns free space for the given directory path. @@ -372,18 +353,3 @@ type freeSpaceEntry struct { updateTime uint64 freeSpace uint64 } - -func mustGetFreeSpace(path string) uint64 { - d, err := os.Open(path) - if err != nil { - logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) - } - defer MustClose(d) - - fd := d.Fd() - var stat unix.Statfs_t - if err := unix.Fstatfs(int(fd), &stat); err != nil { - logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) - } - return freeSpace(stat) -} diff --git a/lib/fs/fs_nix.go b/lib/fs/fs_nix.go index a1e1261270..df7c51fef2 100644 --- a/lib/fs/fs_nix.go +++ b/lib/fs/fs_nix.go @@ -2,7 +2,27 @@ package fs -import "golang.org/x/sys/unix" +import ( + "os" + + "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" + "golang.org/x/sys/unix" +) + +func mustGetFreeSpace(path string) uint64 { + d, err := os.Open(path) + if err != nil { + logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) + } + defer MustClose(d) + + fd := d.Fd() + var stat unix.Statfs_t + if err := unix.Fstatfs(int(fd), &stat); err != nil { + logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) + } + return freeSpace(stat) +} func freeSpace(stat unix.Statfs_t) uint64 { return uint64(stat.Bavail) * uint64(stat.Bsize) diff --git a/lib/fs/fs_openbsd.go b/lib/fs/fs_openbsd.go index 1ab4b93581..9d48a9ee17 100644 --- a/lib/fs/fs_openbsd.go +++ b/lib/fs/fs_openbsd.go @@ -1,9 +1,27 @@ package fs import ( + "os" + + "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "golang.org/x/sys/unix" ) +func mustGetFreeSpace(path string) uint64 { + d, err := os.Open(path) + if err != nil { + logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) + } + defer MustClose(d) + + fd := d.Fd() + var stat unix.Statfs_t + if err := unix.Fstatfs(int(fd), &stat); err != nil { + logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) + } + return freeSpace(stat) +} + func freeSpace(stat unix.Statfs_t) uint64 { return uint64(stat.F_bavail) * uint64(stat.F_bsize) } diff --git a/lib/fs/fs_unix.go b/lib/fs/fs_unix.go new file mode 100644 index 0000000000..ceb27d3a37 --- /dev/null +++ b/lib/fs/fs_unix.go @@ -0,0 +1,45 @@ +// +build linux darwin freebsd openbsd + +package fs + +import ( + "fmt" + "os" + + "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" + "golang.org/x/sys/unix" +) + +func mmap(fd int, offset int64, length int) (data []byte, err error) { + return unix.Mmap(fd, 0, length, unix.PROT_READ, unix.MAP_SHARED) + +} +func mUnmap(data []byte) error { + return unix.Munmap(data) +} + +func mustSyncPath(path string) { + d, err := os.Open(path) + if err != nil { + logger.Panicf("FATAL: cannot open %q: %s", path, err) + } + if err := d.Sync(); err != nil { + _ = d.Close() + logger.Panicf("FATAL: cannot flush %q to storage: %s", path, err) + } + if err := d.Close(); err != nil { + logger.Panicf("FATAL: cannot close %q: %s", path, err) + } +} + +func createFlockFile(dir string) (*os.File, error) { + flockFile := dir + "/flock.lock" + flockF, err := os.Create(flockFile) + if err != nil { + return nil, fmt.Errorf("cannot create lock file %q: %w", flockFile, err) + } + if err := unix.Flock(int(flockF.Fd()), unix.LOCK_EX|unix.LOCK_NB); err != nil { + return nil, fmt.Errorf("cannot acquire lock on file %q: %w", flockFile, err) + } + return flockF, nil +} diff --git a/lib/fs/fs_windows.go b/lib/fs/fs_windows.go new file mode 100644 index 0000000000..e92e3391f9 --- /dev/null +++ b/lib/fs/fs_windows.go @@ -0,0 +1,149 @@ +package fs + +import ( + "fmt" + "os" + "unsafe" + + "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" + "golang.org/x/sys/windows" +) + +var ( + kernelDLL = windows.MustLoadDLL("kernel32.dll") + procLock = kernelDLL.MustFindProc("LockFileEx") + procEvent = kernelDLL.MustFindProc("CreateEventW") + procDisk = kernelDLL.MustFindProc("GetDiskFreeSpaceExW") + ntDLL = windows.MustLoadDLL("ntdll.dll") + ntSetInformationProc = ntDLL.MustFindProc("NtSetInformationFile") +) + +// panic at windows, if file already open by another process. +// one of possible solutions - change files opening process with correct flags. +// https://github.com/dgraph-io/badger/issues/699 +// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-flushfilebuffers +func mustSyncPath(string) { +} + +const ( + lockfileExclusiveLock = 2 + fileFlagNormal = 0x00000080 + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex + fileDispositionPosixSemantics = 0x00000002 + fileDispositionIgnoreReadonlyAttribute = 0x00000010 +) + +// createFlockFile creates flock.lock file in the directory dir +// and returns the handler to the file. +// https://github.com/juju/fslock/blob/master/fslock_windows.go +func createFlockFile(dir string) (*os.File, error) { + flockFile := dir + "/flock.lock" + name, err := windows.UTF16PtrFromString(flockFile) + if err != nil { + return nil, err + } + handle, err := windows.CreateFile( + name, + windows.GENERIC_READ|windows.DELETE, + windows.FILE_SHARE_READ|windows.FILE_SHARE_DELETE, + nil, + windows.OPEN_ALWAYS, + windows.FILE_FLAG_OVERLAPPED|fileFlagNormal, + 0) + if err != nil { + return nil, fmt.Errorf("cannot create lock file %q: %w", flockFile, err) + } + ol, err := newOverlapped() + if err != nil { + return nil, fmt.Errorf("cannot create Overlapped handler: %w", err) + } + // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex + // overlapped is dropped? + r1, _, err := procLock.Call(uintptr(handle), uintptr(lockfileExclusiveLock), uintptr(0), uintptr(1), uintptr(0), uintptr(unsafe.Pointer(ol))) + if r1 == 0 { + return nil, err + } + return os.NewFile(uintptr(handle), flockFile), nil +} + +// stub +func mmap(fd int, offset int64, length int) ([]byte, error) { + return nil, nil +} + +// stub +func mUnmap([]byte) error { + return nil +} + +func mustGetFreeSpace(path string) uint64 { + var freeBytes int64 + r, _, err := procDisk.Call(uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))), + uintptr(unsafe.Pointer(&freeBytes))) + if r == 0 { + logger.Errorf("cannot get free space: %v", err) + return 0 + } + return uint64(freeBytes) +} + +// stub +func fadviseSequentialRead(f *os.File, prefetch bool) error { + return nil +} + +// copied from https://github.com/juju/fslock/blob/master/fslock_windows.go +// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped +func newOverlapped() (*windows.Overlapped, error) { + event, err := createEvent(nil, nil) + if err != nil { + return nil, err + } + return &windows.Overlapped{HEvent: event}, nil +} + +// copied from https://github.com/juju/fslock/blob/master/fslock_windows.go +// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa +func createEvent(sa *windows.SecurityAttributes, name *uint16) (windows.Handle, error) { + r0, _, err := procEvent.Call(uintptr(unsafe.Pointer(sa)), uintptr(1), uintptr(1), uintptr(unsafe.Pointer(name))) + handle := windows.Handle(r0) + if handle == windows.InvalidHandle { + return 0, err + } + return handle, nil +} + +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex +type fileDispositionInformationEx struct { + Flags uint32 +} + +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_status_block +type ioStatusBlock struct { + Status, Information uintptr +} + +// UpdateFileHandle - changes file deletion semantic at windows to posix-like. +func UpdateFileHandle(path string) error { + handle, err := windows.Open(path, windows.GENERIC_READ|windows.DELETE, windows.FILE_SHARE_READ|windows.FILE_SHARE_DELETE) + if err != nil { + return err + } + return setPosixDelete(handle) +} + +// supported starting with Windows 10, version 1709. +// supported by NTFS only. +func setPosixDelete(handle windows.Handle) error { + var iosb ioStatusBlock + flags := fileDispositionInformationEx{ + Flags: fileDispositionPosixSemantics | fileDispositionIgnoreReadonlyAttribute, + } + // class FileDispositionInformationEx, // 64 + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-_file_information_class + r0, _, err := ntSetInformationProc.Call(uintptr(handle), uintptr(unsafe.Pointer(&iosb)), uintptr(unsafe.Pointer(&flags)), unsafe.Sizeof(flags), uintptr(64)) + if r0 == 0 { + return nil + } + return fmt.Errorf("cannot set file disposition information: NT_STATUS: 0x%X, error: %w", r0, err) +} diff --git a/lib/fs/reader_at.go b/lib/fs/reader_at.go index 219bbcbb1f..13850695cb 100644 --- a/lib/fs/reader_at.go +++ b/lib/fs/reader_at.go @@ -7,7 +7,6 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/metrics" - "golang.org/x/sys/unix" ) var disableMmap = flag.Bool("fs.disableMmap", is32BitPtr, "Whether to use pread() instead of mmap() for reading data files. "+ @@ -65,7 +64,7 @@ func (r *ReaderAt) MustReadAt(p []byte, off int64) { func (r *ReaderAt) MustClose() { fname := r.f.Name() if len(r.mmapData) > 0 { - if err := unix.Munmap(r.mmapData[:cap(r.mmapData)]); err != nil { + if err := mUnmap(r.mmapData[:cap(r.mmapData)]); err != nil { logger.Panicf("FATAL: cannot unmap data for file %q: %s", fname, err) } r.mmapData = nil @@ -135,7 +134,7 @@ func mmapFile(f *os.File, size int64) ([]byte, error) { if size%4096 != 0 { size += 4096 - size%4096 } - data, err := unix.Mmap(int(f.Fd()), 0, int(size), unix.PROT_READ, unix.MAP_SHARED) + data, err := mmap(int(f.Fd()), 0, int(size)) if err != nil { return nil, fmt.Errorf("cannot mmap file with size %d: %w", size, err) } diff --git a/lib/procutil/signal.go b/lib/procutil/signal.go index ade5acd2b3..7076b0b715 100644 --- a/lib/procutil/signal.go +++ b/lib/procutil/signal.go @@ -1,3 +1,5 @@ +// +build !windows + package procutil import ( diff --git a/lib/procutil/signal_windows.go b/lib/procutil/signal_windows.go new file mode 100644 index 0000000000..6b16aee73e --- /dev/null +++ b/lib/procutil/signal_windows.go @@ -0,0 +1,60 @@ +// +build windows + +package procutil + +import ( + "os" + "os/signal" + "sync" + "syscall" +) + +// WaitForSigterm waits for either SIGTERM or SIGINT +// +// Returns the caught signal. +// +// Windows dont have SIGHUP syscall. +func WaitForSigterm() os.Signal { + ch := make(chan os.Signal, 1) + signal.Notify(ch, os.Interrupt, syscall.SIGTERM) + sig := <-ch + return sig +} + +type sigHUPNotifier struct { + lock sync.Mutex + subscribers []chan<- os.Signal +} + +var notifier sigHUPNotifier + +// https://golang.org/pkg/os/signal/#hdr-Windows +// https://github.com/golang/go/issues/6948 +// SelfSIGHUP sends SIGHUP signal to the subscribed listeners. +func SelfSIGHUP() { + notifier.notify(syscall.SIGHUP) +} + +// NewSighupChan returns a channel, which is triggered on every SelfSIGHUP. +func NewSighupChan() <-chan os.Signal { + ch := make(chan os.Signal, 1) + notifier.subscribe(ch) + return ch +} + +func (sn *sigHUPNotifier) subscribe(sub chan<- os.Signal) { + sn.lock.Lock() + defer sn.lock.Unlock() + sn.subscribers = append(sn.subscribers, sub) +} + +func (sn *sigHUPNotifier) notify(sig os.Signal) { + sn.lock.Lock() + defer sn.lock.Unlock() + for _, sub := range sn.subscribers { + select { + case sub <- sig: + default: + } + } +} From 7cc3d96a4110f055785e803444aca89c2bcd66d6 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin <valyala@gmail.com> Date: Sat, 27 Feb 2021 01:01:47 +0200 Subject: [PATCH 2/3] lib/fs: follow-up after f3a03c416408bf7d81dee438a10566428962c5ee --- .github/workflows/main.yml | 1 + app/vmagent/Makefile | 4 ---- docs/CHANGELOG.md | 1 + lib/fs/fs.go | 3 ++- lib/fs/fs_nix.go | 18 ------------------ lib/fs/fs_openbsd.go | 18 ------------------ lib/fs/fs_unix.go | 20 +++++++++++++++++--- lib/fs/fs_windows.go | 7 ++----- lib/fs/reader_at.go | 2 +- 9 files changed, 24 insertions(+), 50 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2fcfe52aa9..63e9846b90 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,6 +58,7 @@ jobs: GOOS=darwin go build -mod=vendor ./app/vmbackup GOOS=darwin go build -mod=vendor ./app/vmrestore GOOS=darwin go build -mod=vendor ./app/vmctl + CGO_ENABLED=0 GOOS=windows go build -mod=vendor ./app/vmagent - name: Publish coverage uses: codecov/codecov-action@v1.0.6 with: diff --git a/app/vmagent/Makefile b/app/vmagent/Makefile index e0be998ab3..0ee29504d3 100644 --- a/app/vmagent/Makefile +++ b/app/vmagent/Makefile @@ -73,10 +73,6 @@ vmagent-ppc64le: vmagent-386: CGO_ENABLED=0 GOARCH=386 $(MAKE) vmagent-local-with-goarch -vmagent-windows: - GOOS=windows CGO_ENABLED=0 $(MAKE) vmagent-local-with-goarch - - vmagent-local-with-goarch: APP_NAME=vmagent $(MAKE) app-local-with-goarch diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8ae0db448c..edd86ee81c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -16,6 +16,7 @@ * FEATURE: vmagent: optimize [relabeling](https://victoriametrics.github.io/vmagent.html#relabeling) performance for common cases. * FEATURE: add `increase_pure(m[d])` function to MetricsQL. It works the same as `increase(m[d])` except of various edge cases. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/962) for details. * FEATURE: increase accuracy for `buckets_limit(limit, buckets)` results for small `limit` values. See [MetricsQL docs](https://victoriametrics.github.io/MetricsQL.html) for details. +* FEATURE: vmagent: initial support for Windows build with `CGO_ENABLED=0 GOOS=windows go build -mod=vendor ./app/vmagent`. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/70) and [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1036). * BUGFIX: vmagent: properly perform graceful shutdown on `SIGINT` and `SIGTERM` signals. The graceful shutdown has been broken in `v1.54.0`. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1065 * BUGFIX: reduce the probability of `duplicate time series` errors when querying Kubernetes metrics. diff --git a/lib/fs/fs.go b/lib/fs/fs.go index 8f8c659434..f417f82579 100644 --- a/lib/fs/fs.go +++ b/lib/fs/fs.go @@ -321,7 +321,8 @@ func MustWriteData(w io.Writer, data []byte) { // CreateFlockFile creates flock.lock file in the directory dir // and returns the handler to the file. func CreateFlockFile(dir string) (*os.File, error) { - return createFlockFile(dir) + flockFile := dir + "/flock.lock" + return createFlockFile(flockFile) } // MustGetFreeSpace returns free space for the given directory path. diff --git a/lib/fs/fs_nix.go b/lib/fs/fs_nix.go index df7c51fef2..32df8e641f 100644 --- a/lib/fs/fs_nix.go +++ b/lib/fs/fs_nix.go @@ -3,27 +3,9 @@ package fs import ( - "os" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "golang.org/x/sys/unix" ) -func mustGetFreeSpace(path string) uint64 { - d, err := os.Open(path) - if err != nil { - logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) - } - defer MustClose(d) - - fd := d.Fd() - var stat unix.Statfs_t - if err := unix.Fstatfs(int(fd), &stat); err != nil { - logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) - } - return freeSpace(stat) -} - func freeSpace(stat unix.Statfs_t) uint64 { return uint64(stat.Bavail) * uint64(stat.Bsize) } diff --git a/lib/fs/fs_openbsd.go b/lib/fs/fs_openbsd.go index 9d48a9ee17..1ab4b93581 100644 --- a/lib/fs/fs_openbsd.go +++ b/lib/fs/fs_openbsd.go @@ -1,27 +1,9 @@ package fs import ( - "os" - - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "golang.org/x/sys/unix" ) -func mustGetFreeSpace(path string) uint64 { - d, err := os.Open(path) - if err != nil { - logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) - } - defer MustClose(d) - - fd := d.Fd() - var stat unix.Statfs_t - if err := unix.Fstatfs(int(fd), &stat); err != nil { - logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) - } - return freeSpace(stat) -} - func freeSpace(stat unix.Statfs_t) uint64 { return uint64(stat.F_bavail) * uint64(stat.F_bsize) } diff --git a/lib/fs/fs_unix.go b/lib/fs/fs_unix.go index ceb27d3a37..11df30c8bf 100644 --- a/lib/fs/fs_unix.go +++ b/lib/fs/fs_unix.go @@ -10,7 +10,7 @@ import ( "golang.org/x/sys/unix" ) -func mmap(fd int, offset int64, length int) (data []byte, err error) { +func mmap(fd int, length int) (data []byte, err error) { return unix.Mmap(fd, 0, length, unix.PROT_READ, unix.MAP_SHARED) } @@ -32,8 +32,7 @@ func mustSyncPath(path string) { } } -func createFlockFile(dir string) (*os.File, error) { - flockFile := dir + "/flock.lock" +func createFlockFile(flockFile string) (*os.File, error) { flockF, err := os.Create(flockFile) if err != nil { return nil, fmt.Errorf("cannot create lock file %q: %w", flockFile, err) @@ -43,3 +42,18 @@ func createFlockFile(dir string) (*os.File, error) { } return flockF, nil } + +func mustGetFreeSpace(path string) uint64 { + d, err := os.Open(path) + if err != nil { + logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) + } + defer MustClose(d) + + fd := d.Fd() + var stat unix.Statfs_t + if err := unix.Fstatfs(int(fd), &stat); err != nil { + logger.Panicf("FATAL: cannot determine free disk space on %q: %s", path, err) + } + return freeSpace(stat) +} diff --git a/lib/fs/fs_windows.go b/lib/fs/fs_windows.go index e92e3391f9..a64748cc2b 100644 --- a/lib/fs/fs_windows.go +++ b/lib/fs/fs_windows.go @@ -33,11 +33,8 @@ const ( fileDispositionIgnoreReadonlyAttribute = 0x00000010 ) -// createFlockFile creates flock.lock file in the directory dir -// and returns the handler to the file. // https://github.com/juju/fslock/blob/master/fslock_windows.go -func createFlockFile(dir string) (*os.File, error) { - flockFile := dir + "/flock.lock" +func createFlockFile(flockFile string) (*os.File, error) { name, err := windows.UTF16PtrFromString(flockFile) if err != nil { return nil, err @@ -67,7 +64,7 @@ func createFlockFile(dir string) (*os.File, error) { } // stub -func mmap(fd int, offset int64, length int) ([]byte, error) { +func mmap(fd int, length int) ([]byte, error) { return nil, nil } diff --git a/lib/fs/reader_at.go b/lib/fs/reader_at.go index 13850695cb..53ccb44c37 100644 --- a/lib/fs/reader_at.go +++ b/lib/fs/reader_at.go @@ -134,7 +134,7 @@ func mmapFile(f *os.File, size int64) ([]byte, error) { if size%4096 != 0 { size += 4096 - size%4096 } - data, err := mmap(int(f.Fd()), 0, int(size)) + data, err := mmap(int(f.Fd()), int(size)) if err != nil { return nil, fmt.Errorf("cannot mmap file with size %d: %w", size, err) } From 422b31de40efd49c8176dedddc96c91d0e721d4e Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin <valyala@gmail.com> Date: Sat, 27 Feb 2021 01:45:34 +0200 Subject: [PATCH 3/3] lib/promscrape/discovery/kubernetes: reload k8s resources on every error This is needed for obtaining fresh resourceVersion --- lib/promscrape/discovery/kubernetes/api.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/promscrape/discovery/kubernetes/api.go b/lib/promscrape/discovery/kubernetes/api.go index a11e528c74..112c259df2 100644 --- a/lib/promscrape/discovery/kubernetes/api.go +++ b/lib/promscrape/discovery/kubernetes/api.go @@ -22,7 +22,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils" ) -var apiServerTimeout = flag.Duration("promscrape.kubernetes.apiServerTimeout", 2*time.Minute, "Timeout for requests to Kuberntes API server") +var apiServerTimeout = flag.Duration("promscrape.kubernetes.apiServerTimeout", 10*time.Minute, "How frequently to reload the full state from Kuberntes API server") // apiConfig contains config for API server type apiConfig struct { @@ -345,7 +345,7 @@ func (uw *urlWatcher) watchForUpdates(resourceVersion string) { if err != nil { logger.Errorf("error when performing a request to %q: %s", requestURL, err) backoffSleep() - // There is no sense in reloading resources on non-http errors. + resourceVersion = uw.reloadObjects() continue } if resp.StatusCode != http.StatusOK { @@ -353,27 +353,23 @@ func (uw *urlWatcher) watchForUpdates(resourceVersion string) { _ = resp.Body.Close() logger.Errorf("unexpected status code for request to %q: %d; want %d; response: %q", requestURL, resp.StatusCode, http.StatusOK, body) if resp.StatusCode == 410 { - // Update stale resourceVersion. See https://kubernetes.io/docs/reference/using-api/api-concepts/#410-gone-responses - resourceVersion = uw.reloadObjects() + // There is no need for sleep on 410 error. See https://kubernetes.io/docs/reference/using-api/api-concepts/#410-gone-responses backoffDelay = time.Second } else { backoffSleep() - // There is no sense in reloading resources on non-410 status codes. } + resourceVersion = uw.reloadObjects() continue } backoffDelay = time.Second err = uw.readObjectUpdateStream(resp.Body) _ = resp.Body.Close() if err != nil { - if errors.Is(err, io.EOF) { - // The stream has been closed (probably due to timeout) - backoffSleep() - continue + if !errors.Is(err, io.EOF) { + logger.Errorf("error when reading WatchEvent stream from %q: %s", requestURL, err) } - logger.Errorf("error when reading WatchEvent stream from %q: %s", requestURL, err) backoffSleep() - // There is no sense in reloading resources on non-http errors. + resourceVersion = uw.reloadObjects() continue } }