/** called during recovery (the error message text below assumes that) */ unsigned long long journalReadLSN() { if( !debug ) { // in nondebug build, for now, be conservative until more tests written, and apply the whole journal. // however we will still write the lsn file to exercise that code, and use in _DEBUG build. return 0; } if( !MemoryMappedFile::exists(lsnPath()) ) { log() << "info no lsn file in journal/ directory" << endl; return 0; } try { // os can flush as it likes. if it flushes slowly, we will just do extra work on recovery. // however, given we actually close the file when writing, that seems unlikely. LSNFile L; File f; f.open(lsnPath().string().c_str()); assert(f.is_open()); f.read(0,(char*)&L, sizeof(L)); unsigned long long lsn = L.get(); return lsn; } catch(std::exception& e) { uasserted(13611, str::stream() << "can't read lsn file in journal directory : " << e.what()); } return 0; }
/** throws */ void removeJournalFiles() { log() << "removeJournalFiles" << endl; try { for ( boost::filesystem::directory_iterator i( getJournalDir() ); i != boost::filesystem::directory_iterator(); ++i ) { string fileName = boost::filesystem::path(*i).leaf(); if( str::startsWith(fileName, "j._") ) { try { boost::filesystem::remove(*i); } catch(std::exception& e) { log() << "couldn't remove " << fileName << ' ' << e.what() << endl; throw; } } } try { boost::filesystem::remove(lsnPath()); } catch(...) { log() << "couldn't remove " << lsnPath().string() << endl; throw; } } catch( std::exception& e ) { log() << "error removing journal files " << e.what() << endl; throw; } assert(!haveJournalFiles()); log(1) << "removeJournalFiles end" << endl; }
/** remember "last sequence number" to speed recoveries concurrency: called by durThread only. */ void Journal::updateLSNFile() { if( !_writeToLSNNeeded ) return; durThreadMain.assertWithin(); _writeToLSNNeeded = false; try { // os can flush as it likes. if it flushes slowly, we will just do extra work on recovery. // however, given we actually close the file, that seems unlikely. File f; f.open(lsnPath().string().c_str()); if( !f.is_open() ) { // can get 0 if an i/o error log() << "warning: open of lsn file failed" << endl; return; } log() << "lsn set " << _lastFlushTime << endl; LSNFile lsnf; lsnf.set(_lastFlushTime); f.write(0, (char*)&lsnf, sizeof(lsnf)); } catch(std::exception& e) { log() << "warning: write to lsn file failed " << e.what() << endl; // keep running (ignore the error). recovery will be slow. } }
/** remember "last sequence number" to speed recoveries */ void lsnThread() { Client::initThread("lsn"); time_t last = 0; while( 1 ) { unsigned long long lsn = j.toStoreLastSeqNum.take(); // if you are on a really fast fsync interval, we don't write this as often if( time(0) - last < 5 ) continue; last = time(0); try { // os can flush as it likes. if it flushes slowly, we will just do extra work on recovery. // however, given we actually close the file, that seems unlikely. MemoryMappedFile f; unsigned long long length = 8; unsigned long long *L = static_cast<unsigned long long*>(f.map(lsnPath().string().c_str(), length)); assert(L); *L = lsn; } catch(std::exception& e) { log() << "write to lsn file fails " << e.what() << endl; } } }
unsigned long long journalReadLSN() { try { // os can flush as it likes. if it flushes slowly, we will just do extra work on recovery. // however, given we actually close the file, that seems unlikely. MemoryMappedFile f; unsigned long long *L = static_cast<unsigned long long*>(f.map(lsnPath().string().c_str())); assert(L); return *L; } catch(std::exception& e) { log() << "couldn't read journal/lsn file - if a recovery is needed will apply all files. " << e.what() << endl; } return 0; }