diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index faf275d26d8..6f4134c9b21 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -57,6 +57,7 @@ https://github.com/elastic/beats/compare/v5.0.0-alpha5...master[Check the HEAD d - Fix processor failure in Filebeat when using regex, contain, or equals with the message field. {issue}2178[2178] *Winlogbeat* +- Fix corrupt registry file that occurs on power loss by disabling file write caching. {issue}2313[2313] ==== Added diff --git a/winlogbeat/checkpoint/checkpoint.go b/winlogbeat/checkpoint/checkpoint.go index c421faea66c..4d473a71833 100644 --- a/winlogbeat/checkpoint/checkpoint.go +++ b/winlogbeat/checkpoint/checkpoint.go @@ -105,6 +105,7 @@ func NewCheckpoint(file string, maxUpdates int, interval time.Duration) (*Checkp // the amount of time since the last disk write reaches flushInterval. func (c *Checkpoint) run() { defer c.wg.Done() + defer c.persist() flushTimer := time.NewTimer(c.flushInterval) defer flushTimer.Stop() @@ -127,8 +128,6 @@ loop: c.persist() flushTimer.Reset(c.flushInterval) } - - c.persist() } // Shutdown stops the checkpoint worker (which persists any state to disk as @@ -185,7 +184,7 @@ func (c *Checkpoint) persist() bool { // flush writes the current state to disk. func (c *Checkpoint) flush() error { tempFile := c.file + ".new" - file, err := os.Create(tempFile) + file, err := create(tempFile) if os.IsNotExist(err) { // Try to create directory if it does not exist. if createDirErr := c.createDir(); createDirErr == nil { diff --git a/winlogbeat/checkpoint/file_unix.go b/winlogbeat/checkpoint/file_unix.go new file mode 100644 index 00000000000..d16c821dc53 --- /dev/null +++ b/winlogbeat/checkpoint/file_unix.go @@ -0,0 +1,9 @@ +// +build !windows + +package checkpoint + +import "os" + +func create(path string) (*os.File, error) { + return os.Create(path) +} diff --git a/winlogbeat/checkpoint/file_windows.go b/winlogbeat/checkpoint/file_windows.go new file mode 100644 index 00000000000..40ada0bf36c --- /dev/null +++ b/winlogbeat/checkpoint/file_windows.go @@ -0,0 +1,37 @@ +package checkpoint + +import ( + "os" + "syscall" +) + +const ( + _FILE_FLAG_WRITE_THROUGH = 0x80000000 +) + +func create(path string) (*os.File, error) { + return createWriteThroughFile(path) +} + +// createWriteThroughFile creates a file whose write operations do not go +// through any intermediary cache, they go directly to disk. +func createWriteThroughFile(path string) (*os.File, error) { + if len(path) == 0 { + return nil, syscall.ERROR_FILE_NOT_FOUND + } + pathp, err := syscall.UTF16PtrFromString(path) + if err != nil { + return nil, err + } + + h, err := syscall.CreateFile( + pathp, // Path + syscall.GENERIC_READ|syscall.GENERIC_WRITE, // Access Mode + uint32(syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE), // Share Mode + nil, // Security Attributes + syscall.CREATE_ALWAYS, // Create Mode + uint32(syscall.FILE_ATTRIBUTE_NORMAL|_FILE_FLAG_WRITE_THROUGH), // Flags and Attributes + 0) // Template File + + return os.NewFile(uintptr(h), path), err +}