diff options
Diffstat (limited to 'src/mongo/db/durop.cpp')
-rw-r--r-- | src/mongo/db/durop.cpp | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/mongo/db/durop.cpp b/src/mongo/db/durop.cpp new file mode 100644 index 00000000000..80ee5043410 --- /dev/null +++ b/src/mongo/db/durop.cpp @@ -0,0 +1,161 @@ +// @file durop.cpp + +/** +* Copyright (C) 2010 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 "concurrency.h" +#include "../util/alignedbuilder.h" +#include "../util/mongoutils/str.h" +#include "../util/file.h" +#include "mongommf.h" +#include "durop.h" +#include "../util/file_allocator.h" + +using namespace mongoutils; + +namespace mongo { + + extern string dbpath; // --dbpath parm + + void _deleteDataFiles(const char *); + + namespace dur { + + /** read a durop from journal file referenced by br. + @param opcode the opcode which has already been written from the bufreader + */ + shared_ptr<DurOp> DurOp::read(unsigned opcode, BufReader& br) { + shared_ptr<DurOp> op; + switch( opcode ) { + case JEntry::OpCode_FileCreated: + op = shared_ptr<DurOp>( new FileCreatedOp(br) ); + break; + case JEntry::OpCode_DropDb: + op = shared_ptr<DurOp>( new DropDbOp(br) ); + break; + default: + massert(13546, (str::stream() << "journal recover: unrecognized opcode in journal " << opcode), false); + } + return op; + } + + void DurOp::serialize(AlignedBuilder& ab) { + ab.appendNum(_opcode); + _serialize(ab); + } + + DropDbOp::DropDbOp(BufReader& log) : DurOp(JEntry::OpCode_DropDb) { + unsigned long long reserved; + log.read(reserved); + log.read(reserved); + log.readStr(_db); + string reservedStr; + log.readStr(reservedStr); + } + + void DropDbOp::_serialize(AlignedBuilder& ab) { + ab.appendNum((unsigned long long) 0); // reserved for future use + ab.appendNum((unsigned long long) 0); // reserved for future use + ab.appendStr(_db); + ab.appendStr(""); // reserved + } + + /** throws */ + void DropDbOp::replay() { + log() << "recover replay drop db " << _db << endl; + _deleteDataFiles(_db.c_str()); + } + + FileCreatedOp::FileCreatedOp(string f, unsigned long long l) : + DurOp(JEntry::OpCode_FileCreated) { + _p = RelativePath::fromFullPath(f); + _len = l; + } + + FileCreatedOp::FileCreatedOp(BufReader& log) : DurOp(JEntry::OpCode_FileCreated) { + unsigned long long reserved; + log.read(reserved); + log.read(reserved); + log.read(_len); // size of file, not length of name + string s; + log.readStr(s); + _p._p = s; + } + + void FileCreatedOp::_serialize(AlignedBuilder& ab) { + ab.appendNum((unsigned long long) 0); // reserved for future use + ab.appendNum((unsigned long long) 0); // reserved for future use + ab.appendNum(_len); + ab.appendStr(_p.toString()); + } + + string FileCreatedOp::toString() { + return str::stream() << "FileCreatedOp " << _p.toString() << ' ' << _len/1024.0/1024.0 << "MB"; + } + + // if an operation deletes or creates a file (or moves etc.), it may need files closed. + bool FileCreatedOp::needFilesClosed() { + return exists( _p.asFullPath() ); + } + + void FileCreatedOp::replay() { + // i believe the code assumes new files are filled with zeros. thus we have to recreate the file, + // or rewrite at least, even if it were the right length. perhaps one day we should change that + // although easier to avoid defects if we assume it is zeros perhaps. + string full = _p.asFullPath(); + if( exists(full) ) { + try { + remove(full); + } + catch(std::exception& e) { + log(1) << "recover info FileCreateOp::replay unlink " << e.what() << endl; + } + } + + log() << "recover create file " << full << ' ' << _len/1024.0/1024.0 << "MB" << endl; + if( MemoryMappedFile::exists(full) ) { + // first delete if exists. + try { + remove(full); + } + catch(...) { + log() << "warning could not delete file " << full << endl; + } + } + ensureParentDirCreated(full); + File f; + f.open(full.c_str()); + massert(13547, str::stream() << "recover couldn't create file " << full, f.is_open()); + unsigned long long left = _len; + const unsigned blksz = 64 * 1024; + scoped_array<char> v( new char[blksz] ); + memset( v.get(), 0, blksz ); + fileofs ofs = 0; + while( left ) { + unsigned long long w = left < blksz ? left : blksz; + f.write(ofs, v.get(), (unsigned) w); + left -= w; + ofs += w; + } + f.fsync(); + flushMyDirectory(full); + massert(13628, str::stream() << "recover failure writing file " << full, !f.bad() ); + } + + } + +} |