Files
mongo/util/logfile.cpp

254 lines
7.5 KiB
C++
Raw Normal View History

2010-11-06 21:29:49 -04:00
// @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"
2010-11-08 09:21:33 -05:00
#include "unittest.h"
2010-11-06 21:29:49 -04:00
using namespace mongoutils;
namespace mongo {
2011-01-04 00:40:41 -05:00
struct LogfileTest : public UnitTest {
LogfileTest() { }
void run() {
2010-11-08 09:21:33 -05:00
if( 0 && debug ) {
2011-01-04 00:40:41 -05:00
try {
2010-11-08 09:21:33 -05:00
LogFile f("logfile_test");
2010-12-08 16:23:21 -05:00
void *p = malloc(16384);
2010-11-08 09:21:33 -05:00
char *buf = (char*) p;
2010-12-08 16:23:21 -05:00
buf += 4095;
buf = (char*) (((size_t)buf)&(~0xfff));
2010-11-08 09:21:33 -05:00
memset(buf, 'z', 8192);
buf[8190] = '\n';
buf[8191] = 'B';
2010-11-06 21:29:49 -04:00
buf[0] = 'A';
2010-11-08 09:21:33 -05:00
f.synchronousAppend(buf, 8192);
f.synchronousAppend(buf, 8192);
2010-12-08 16:23:21 -05:00
free(p);
2010-11-06 21:29:49 -04:00
}
2011-01-04 00:40:41 -05:00
catch(DBException& e ) {
2010-12-08 16:23:21 -05:00
log() << "logfile.cpp test failed : " << e.what() << endl;
throw;
2010-11-06 21:29:49 -04:00
}
}
}
} __test;
}
#if defined(_WIN32)
2011-01-04 00:40:41 -05:00
namespace mongo {
2010-11-06 21:29:49 -04:00
2011-11-07 13:40:35 -05:00
LogFile::LogFile(string name, bool readwrite) : _name(name) {
2010-11-06 21:29:49 -04:00
_fd = CreateFile(
2011-01-04 00:40:41 -05:00
toNativeString(name.c_str()).c_str(),
2011-11-07 13:40:35 -05:00
(readwrite?GENERIC_READ:0)|GENERIC_WRITE,
2011-01-04 00:40:41 -05:00
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
2011-01-04 00:40:41 -05:00
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
NULL);
2010-11-10 13:42:08 -05:00
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);
2010-11-10 13:42:08 -05:00
}
2010-11-08 09:21:33 -05:00
2011-01-04 00:40:41 -05:00
LogFile::~LogFile() {
2010-11-08 09:21:33 -05:00
if( _fd != INVALID_HANDLE_VALUE )
CloseHandle(_fd);
2010-11-06 21:29:49 -04:00
}
void LogFile::truncate() {
verify(15870, _fd != INVALID_HANDLE_VALUE);
if (!SetEndOfFile(_fd)){
msgasserted(15871, "Couldn't truncate file: " + errnoWithDescription());
}
}
2011-11-10 15:11:17 -05:00
void LogFile::writeAt(unsigned long long offset, const void *_buf, size_t _len) {
// TODO 64 bit offsets
2011-11-06 17:42:44 -05:00
OVERLAPPED o;
memset(&o,0,sizeof(o));
2011-11-10 16:15:53 -05:00
(unsigned long long&) o.Offset = offset;
2011-11-06 17:42:44 -05:00
BOOL ok= WriteFile(_fd, _buf, _len, 0, &o);
assert(ok);
}
2011-11-10 15:11:17 -05:00
void LogFile::readAt(unsigned long long offset, void *_buf, size_t _len) {
// TODO 64 bit offsets
2011-11-07 13:40:35 -05:00
OVERLAPPED o;
memset(&o,0,sizeof(o));
2011-11-10 16:15:53 -05:00
(unsigned long long&) o.Offset = offset;
2011-11-07 13:40:35 -05:00
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;
assert(false);
}
}
void LogFile::synchronousAppend(const void *_buf, size_t _len) {
const size_t BlockSize = 8 * 1024 * 1024;
2010-11-06 21:29:49 -04:00
assert(_fd);
2011-07-21 17:08:25 -04:00
assert(_len % 4096 == 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 )
2011-07-21 17:08:25 -04:00
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;
2010-11-06 21:29:49 -04:00
}
}
}
#else
2011-11-07 13:40:35 -05:00
/// posix
2010-11-08 09:21:33 -05:00
#include <sys/types.h>
#include <sys/stat.h>
2010-11-06 21:29:49 -04:00
#include <fcntl.h>
#include "paths.h"
2010-11-06 21:29:49 -04:00
2011-01-04 00:40:41 -05:00
namespace mongo {
2010-11-06 21:29:49 -04:00
2011-11-07 13:40:35 -05:00
LogFile::LogFile(string name, bool readwrite) : _name(name) {
int options = O_CREAT
2011-11-07 13:40:35 -05:00
| (readwrite?O_RDWR:O_WRONLY)
2010-11-06 21:29:49 -04:00
#if defined(O_DIRECT)
| O_DIRECT
2010-11-06 21:29:49 -04:00
#endif
#if defined(O_NOATIME)
| O_NOATIME
2010-11-06 21:29:49 -04:00
#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
2010-11-08 09:21:33 -05:00
if( _fd < 0 ) {
2010-11-10 13:42:08 -05:00
uasserted(13516, str::stream() << "couldn't open file " << name << " for writing " << errnoWithDescription());
2010-11-08 09:21:33 -05:00
}
flushMyDirectory(name);
2010-11-06 21:29:49 -04:00
}
2011-01-04 00:40:41 -05:00
LogFile::~LogFile() {
2010-11-08 09:21:33 -05:00
if( _fd >= 0 )
close(_fd);
2010-12-08 16:23:21 -05:00
_fd = -1;
2010-11-08 09:21:33 -05:00
}
void LogFile::truncate() {
verify(15872, _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);
}
2011-11-10 15:11:17 -05:00
void LogFile::writeAt(unsigned long long offset, const void *buf, size_t len) {
2011-11-07 15:36:45 -05:00
assert(((size_t)buf)%4096==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
}
2011-11-10 15:11:17 -05:00
void LogFile::readAt(unsigned long long offset, void *_buf, size_t _len) {
2011-11-07 15:36:45 -05:00
assert(((size_t)_buf)%4096==0); // aligned
2011-11-09 09:02:25 -05:00
ssize_t rd = pread(_fd, _buf, _len, offset);
assert( rd != -1 );
2011-11-07 15:36:45 -05:00
}
2010-11-15 22:55:19 -05:00
void LogFile::synchronousAppend(const void *b, size_t len) {
#ifdef POSIX_FADV_DONTNEED
2011-11-10 15:11:17 -05:00
const off_t pos = lseek(_fd, 0, SEEK_CUR); // doesn't actually seek, just get current position
#endif
2010-11-15 22:55:19 -05:00
const char *buf = (char *) b;
2010-11-06 21:29:49 -04:00
assert(_fd);
2010-12-08 16:23:21 -05:00
assert(((size_t)buf)%4096==0); // aligned
2011-01-04 00:40:41 -05:00
if( len % 4096 != 0 ) {
2010-12-08 16:23:21 -05:00
log() << len << ' ' << len % 4096 << endl;
assert(false);
}
2010-11-06 21:29:49 -04:00
ssize_t written = write(_fd, buf, len);
2011-01-04 00:40:41 -05:00
if( written != (ssize_t) len ) {
2011-03-01 16:28:44 -05:00
log() << "write fails written:" << written << " len:" << len << " buf:" << buf << ' ' << errnoWithDescription() << endl;
2011-01-25 14:37:01 -05:00
uasserted(13515, str::stream() << "error appending to file " << _fd << ' ' << errnoWithDescription());
2010-11-06 21:29:49 -04:00
}
2011-02-03 11:23:27 -05:00
if(
#if defined(__linux__)
fdatasync(_fd) < 0
#else
fsync(_fd)
#endif
) {
2011-01-25 14:37:01 -05:00
uasserted(13514, str::stream() << "error appending to file on fsync " << ' ' << errnoWithDescription());
2010-11-06 21:29:49 -04:00
}
#ifdef POSIX_FADV_DONTNEED
if (!_direct)
posix_fadvise(_fd, pos, len, POSIX_FADV_DONTNEED);
#endif
2010-11-06 21:29:49 -04:00
}
}
#endif