summaryrefslogtreecommitdiff
path: root/src/mongo/util/logfile.cpp
diff options
context:
space:
mode:
authorAntonin Kral <a.kral@bobek.cz>2012-08-29 20:54:51 +0200
committerAntonin Kral <a.kral@bobek.cz>2012-08-29 20:54:51 +0200
commit83957b73f9177f6e38bd5375bd93ca1f6a47188c (patch)
treef20b7d6ac9a9c64ff5bb6b5910a24abbb356b1d5 /src/mongo/util/logfile.cpp
parent5071d203970edd4c995493d810abe20987e76fe9 (diff)
Imported Upstream version 2.2.0upstream/2.2.0
Diffstat (limited to 'src/mongo/util/logfile.cpp')
-rw-r--r--src/mongo/util/logfile.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/mongo/util/logfile.cpp b/src/mongo/util/logfile.cpp
new file mode 100644
index 00000000000..d5aa99ee743
--- /dev/null
+++ b/src/mongo/util/logfile.cpp
@@ -0,0 +1,262 @@
+// @file logfile.cpp simple file log writing / journaling
+
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "pch.h"
+#include "logfile.h"
+#include "text.h"
+#include "mongoutils/str.h"
+#include "mongo/util/startup_test.h"
+#include "mongo/util/mmap.h"
+
+using namespace mongoutils;
+
+namespace mongo {
+ struct LogfileTest : public StartupTest {
+ LogfileTest() { }
+ void run() {
+ if( 0 && debug ) {
+ try {
+ LogFile f("logfile_test");
+ void *p = malloc(16384);
+ char *buf = (char*) p;
+ buf += 4095;
+ buf = (char*) (((size_t)buf)&(~0xfff));
+ memset(buf, 'z', 8192);
+ buf[8190] = '\n';
+ buf[8191] = 'B';
+ buf[0] = 'A';
+ f.synchronousAppend(buf, 8192);
+ f.synchronousAppend(buf, 8192);
+ free(p);
+ }
+ catch(DBException& e ) {
+ log() << "logfile.cpp test failed : " << e.what() << endl;
+ throw;
+ }
+ }
+ }
+ } __test;
+}
+
+#if defined(_WIN32)
+
+namespace mongo {
+
+ LogFile::LogFile(string name, bool readwrite) : _name(name) {
+ _fd = CreateFile(
+ toNativeString(name.c_str()).c_str(),
+ (readwrite?GENERIC_READ:0)|GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
+ NULL);
+ if( _fd == INVALID_HANDLE_VALUE ) {
+ DWORD e = GetLastError();
+ uasserted(13518, str::stream() << "couldn't open file " << name << " for writing " << errnoWithDescription(e));
+ }
+ SetFilePointer(_fd, 0, 0, FILE_BEGIN);
+ }
+
+ LogFile::~LogFile() {
+ if( _fd != INVALID_HANDLE_VALUE )
+ CloseHandle(_fd);
+ }
+
+ void LogFile::truncate() {
+ verify(_fd != INVALID_HANDLE_VALUE);
+
+ if (!SetEndOfFile(_fd)){
+ msgasserted(15871, "Couldn't truncate file: " + errnoWithDescription());
+ }
+ }
+
+ void LogFile::writeAt(unsigned long long offset, const void *_buf, size_t _len) {
+// TODO 64 bit offsets
+ OVERLAPPED o;
+ memset(&o,0,sizeof(o));
+ (unsigned long long&) o.Offset = offset;
+ BOOL ok= WriteFile(_fd, _buf, _len, 0, &o);
+ verify(ok);
+ }
+
+ void LogFile::readAt(unsigned long long offset, void *_buf, size_t _len) {
+// TODO 64 bit offsets
+ OVERLAPPED o;
+ memset(&o,0,sizeof(o));
+ (unsigned long long&) o.Offset = offset;
+ DWORD nr;
+ BOOL ok = ReadFile(_fd, _buf, _len, &nr, &o);
+ if( !ok ) {
+ string e = errnoWithDescription();
+ //DWORD e = GetLastError();
+ log() << "LogFile readAt(" << offset << ") len:" << _len << "errno:" << e << endl;
+ verify(false);
+ }
+ }
+
+ void LogFile::synchronousAppend(const void *_buf, size_t _len) {
+ const size_t BlockSize = 8 * 1024 * 1024;
+ verify(_fd);
+ verify(_len % g_minOSPageSizeBytes == 0);
+ const char *buf = (const char *) _buf;
+ size_t left = _len;
+ while( left ) {
+ size_t toWrite = min(left, BlockSize);
+ DWORD written;
+ if( !WriteFile(_fd, buf, toWrite, &written, NULL) ) {
+ DWORD e = GetLastError();
+ if( e == 87 )
+ msgasserted(13519, "error 87 appending to file - invalid parameter");
+ else
+ uasserted(13517, str::stream() << "error appending to file " << _name << ' ' << _len << ' ' << toWrite << ' ' << errnoWithDescription(e));
+ }
+ else {
+ dassert( written == toWrite );
+ }
+ left -= written;
+ buf += written;
+ }
+ }
+
+}
+
+#else
+
+/// posix
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "paths.h"
+
+namespace mongo {
+
+ LogFile::LogFile(string name, bool readwrite) : _name(name) {
+ int options = O_CREAT
+ | (readwrite?O_RDWR:O_WRONLY)
+#if defined(O_DIRECT)
+ | O_DIRECT
+#endif
+#if defined(O_NOATIME)
+ | O_NOATIME
+#endif
+ ;
+
+ _fd = open(name.c_str(), options, S_IRUSR | S_IWUSR);
+
+#if defined(O_DIRECT)
+ _direct = true;
+ if( _fd < 0 ) {
+ _direct = false;
+ options &= ~O_DIRECT;
+ _fd = open(name.c_str(), options, S_IRUSR | S_IWUSR);
+ }
+#else
+ _direct = false;
+#endif
+
+ if( _fd < 0 ) {
+ uasserted(13516, str::stream() << "couldn't open file " << name << " for writing " << errnoWithDescription());
+ }
+
+ flushMyDirectory(name);
+ }
+
+ LogFile::~LogFile() {
+ if( _fd >= 0 )
+ close(_fd);
+ _fd = -1;
+ }
+
+ void LogFile::truncate() {
+ verify(_fd >= 0);
+
+ BOOST_STATIC_ASSERT(sizeof(off_t) == 8); // we don't want overflow here
+ const off_t pos = lseek(_fd, 0, SEEK_CUR); // doesn't actually seek
+ if (ftruncate(_fd, pos) != 0){
+ msgasserted(15873, "Couldn't truncate file: " + errnoWithDescription());
+ }
+
+ fsync(_fd);
+ }
+
+ void LogFile::writeAt(unsigned long long offset, const void *buf, size_t len) {
+ verify(((size_t)buf) % g_minOSPageSizeBytes == 0); // aligned
+ ssize_t written = pwrite(_fd, buf, len, offset);
+ if( written != (ssize_t) len ) {
+ log() << "writeAt fails " << errnoWithDescription() << endl;
+ }
+#if defined(__linux__)
+ fdatasync(_fd);
+#else
+ fsync(_fd);
+#endif
+ }
+
+ void LogFile::readAt(unsigned long long offset, void *_buf, size_t _len) {
+ verify(((size_t)_buf) % g_minOSPageSizeBytes == 0); // aligned
+ ssize_t rd = pread(_fd, _buf, _len, offset);
+ verify( rd != -1 );
+ }
+
+ void LogFile::synchronousAppend(const void *b, size_t len) {
+
+ const char *buf = static_cast<const char *>( b );
+ ssize_t charsToWrite = static_cast<ssize_t>( len );
+
+ fassert( 16144, charsToWrite >= 0 );
+ fassert( 16142, _fd >= 0 );
+ fassert( 16143, reinterpret_cast<ssize_t>( buf ) % g_minOSPageSizeBytes == 0 ); // aligned
+
+#ifdef POSIX_FADV_DONTNEED
+ const off_t pos = lseek(_fd, 0, SEEK_CUR); // doesn't actually seek, just get current position
+#endif
+
+ while ( charsToWrite > 0 ) {
+ const ssize_t written = write( _fd, buf, static_cast<size_t>( charsToWrite ) );
+ if ( -1 == written ) {
+ log() << "LogFile::synchronousAppend failed with " << charsToWrite
+ << " bytes unwritten out of " << len << " bytes; b=" << b << ' '
+ << errnoWithDescription() << std::endl;
+ fassertFailed( 13515 );
+ }
+ buf += written;
+ charsToWrite -= written;
+ }
+
+ if(
+#if defined(__linux__)
+ fdatasync(_fd) < 0
+#else
+ fsync(_fd)
+#endif
+ ) {
+ log() << "error appending to file on fsync " << ' ' << errnoWithDescription();
+ fassertFailed( 13514 );
+ }
+
+#ifdef POSIX_FADV_DONTNEED
+ if (!_direct)
+ posix_fadvise(_fd, pos, len, POSIX_FADV_DONTNEED);
+#endif
+ }
+
+}
+
+#endif