Browse Source

fix(LogFile): Unify flushing behaviour of WIN32 and STD implementation (#2443)

Matej Kenda 2 years ago
parent
commit
eb51c78305

+ 15 - 5
Foundation/src/LogFile_STD.cpp

@@ -16,6 +16,7 @@
 #include "Poco/File.h"
 #include "Poco/Exception.h"
 
+#include <unistd.h>
 
 namespace Poco {
 
@@ -40,17 +41,26 @@ LogFileImpl::~LogFileImpl()
 void LogFileImpl::writeImpl(const std::string& text, bool flush)
 {
 	std::streampos pos = _str.tellp();
-	_str << text;
-	if (flush)
-		_str << std::endl;
-	else
-		_str << "\n";
+
+	_str << text << '\n';
+
+	// Flush the stream buffer to file to match the implementation on Windows
+	_str.flush();
+
 	if (!_str.good())
 	{
 		_str.clear();
 		_str.seekp(pos);
 		throw WriteFileException(_path);
 	}
+
+	if (flush)
+	{
+		// Sync the file to disk as it is done on Windows
+		if (fsync(_str.nativeHandle()) != 0)
+			throw WriteFileException(_path);
+	}
+
 	_size = static_cast<UInt64>(_str.tellp());
 }
 

+ 2 - 0
Foundation/src/LogFile_WIN32U.cpp

@@ -17,6 +17,8 @@
 #include "Poco/Exception.h"
 #include "Poco/UnicodeConverter.h"
 
+// TODO: LogStream shall use FileOutputStream for all implementations (see LogStream_STD)
+// TODO: Implement flushToDisk function in FileOutputStream.
 
 namespace Poco {
 

+ 54 - 0
Foundation/testsuite/src/FileChannelTest.cpp

@@ -86,6 +86,59 @@ void FileChannelTest::testRotateNever()
 }
 
 
+void FileChannelTest::testFlushing()
+{
+	std::string name = filename();
+	try
+	{
+		AutoPtr<FileChannel> pChannel = new FileChannel(name);
+		pChannel->setProperty(FileChannel::PROP_FLUSH, "false");
+		pChannel->open();
+		Message msg("source", "01234567890123456789", Message::PRIO_INFORMATION);
+		pChannel->log(msg);
+
+		// File shall be there and have content after writing first message.
+		File f(name);
+		assertTrue (f.exists());
+		assertTrue (f.getSize() >= 20);
+
+		Timestamp::TimeDiff noFlushTime;
+		{
+			Timestamp start;
+			for (int i = 0; i < 2000; ++i)
+			{
+				pChannel->log(msg);
+			}
+			pChannel->close();
+			Timestamp end;
+			noFlushTime = end-start;
+		}
+		Timestamp::TimeDiff flushTime;
+		{
+			pChannel->setProperty(FileChannel::PROP_FLUSH, "true");
+			pChannel->open();
+			Timestamp start;
+			for (int i = 0; i < 2000; ++i)
+			{
+				pChannel->log(msg);
+			}
+			pChannel->close();
+			Timestamp end;
+			flushTime = end-start;
+		}
+
+		// Writing to channel with flushing is expected to be slower.
+		assertTrue(flushTime > noFlushTime);
+	}
+	catch (...)
+	{
+		remove(name);
+		throw;
+	}
+	remove(name);
+}
+
+
 void FileChannelTest::testRotateBySize()
 {
 	std::string name = filename();
@@ -832,6 +885,7 @@ CppUnit::Test* FileChannelTest::suite()
 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileChannelTest");
 
 	CppUnit_addTest(pSuite, FileChannelTest, testRotateNever);
+	CppUnit_addTest(pSuite, FileChannelTest, testFlushing);
 	CppUnit_addTest(pSuite, FileChannelTest, testRotateBySize);
 	CppUnit_addTest(pSuite, FileChannelTest, testRotateByAge);
 	CppUnit_addLongTest(pSuite, FileChannelTest, testRotateAtTimeDayUTC);

+ 1 - 0
Foundation/testsuite/src/FileChannelTest.h

@@ -32,6 +32,7 @@ public:
 	~FileChannelTest();
 
 	void testRotateNever();
+	void testFlushing();
 	void testRotateBySize();
 	void testRotateByAge();
 	void testRotateAtTimeDayUTC();