boost::filesystem::path ensureParentDirCreated(const boost::filesystem::path& p){ const boost::filesystem::path parent = p.branch_path(); if (! boost::filesystem::exists(parent)){ ensureParentDirCreated(parent); log() << "creating directory " << parent.string() << endl; boost::filesystem::create_directory(parent); flushMyDirectory(parent); // flushes grandparent to ensure parent exists after crash } assert(boost::filesystem::is_directory(parent)); return parent; }
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( boost::filesystem::exists(full) ) { try { boost::filesystem::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( boost::filesystem::exists(full) ) { // first delete if exists. try { boost::filesystem::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() ); }
void FileAllocator::run( FileAllocator * fa ) { setThreadName( "FileAllocator" ); while( 1 ) { { scoped_lock lk( fa->_pendingMutex ); if ( fa->_pending.size() == 0 ) fa->_pendingUpdated.wait( lk.boost() ); } while( 1 ) { string name; long size; { scoped_lock lk( fa->_pendingMutex ); if ( fa->_pending.size() == 0 ) break; name = fa->_pending.front(); size = fa->_pendingSize[ name ]; } string tmp; long fd = 0; try { log() << "allocating new datafile " << name << ", filling with zeroes..." << endl; boost::filesystem::path parent = ensureParentDirCreated(name); tmp = makeTempFileName( parent ); ensureParentDirCreated(tmp); fd = open(tmp.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR); if ( fd <= 0 ) { log() << "FileAllocator: couldn't create " << name << " (" << tmp << ") " << errnoWithDescription() << endl; uasserted(10439, ""); } #if defined(POSIX_FADV_DONTNEED) if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTNEED) ) { log() << "warning: posix_fadvise fails " << name << " (" << tmp << ") " << errnoWithDescription() << endl; } #endif Timer t; /* make sure the file is the full desired length */ ensureLength( fd , size ); close( fd ); fd = 0; if( rename(tmp.c_str(), name.c_str()) ) { log() << "error: couldn't rename " << tmp << " to " << name << ' ' << errnoWithDescription() << endl; uasserted(13653, ""); } flushMyDirectory(name); log() << "done allocating datafile " << name << ", " << "size: " << size/1024/1024 << "MB, " << " took " << ((double)t.millis())/1000.0 << " secs" << endl; // no longer in a failed state. allow new writers. fa->_failed = false; } catch ( ... ) { if ( fd > 0 ) close( fd ); log() << "error failed to allocate new file: " << name << " size: " << size << ' ' << errnoWithDescription() << warnings; log() << " will try again in 10 seconds" << endl; // not going to warning logs try { if ( tmp.size() ) MONGO_ASSERT_ON_EXCEPTION( boost::filesystem::remove( tmp ) ); MONGO_ASSERT_ON_EXCEPTION( boost::filesystem::remove( name ) ); } catch ( ... ) { } scoped_lock lk( fa->_pendingMutex ); fa->_failed = true; // not erasing from pending fa->_pendingUpdated.notify_all(); sleepsecs(10); continue; } { scoped_lock lk( fa->_pendingMutex ); fa->_pendingSize.erase( name ); fa->_pending.pop_front(); fa->_pendingUpdated.notify_all(); } } } }
void FileAllocator::run( FileAllocator * fa ) { setThreadName( "FileAllocator" ); { // initialize unique temporary file name counter // TODO: SERVER-6055 -- Unify temporary file name selection SimpleMutex::scoped_lock lk(_uniqueNumberMutex); _uniqueNumber = curTimeMicros64(); } while( 1 ) { { scoped_lock lk( fa->_pendingMutex ); if ( fa->_pending.size() == 0 ) fa->_pendingUpdated.wait( lk.boost() ); } while( 1 ) { string name; long size = 0; { scoped_lock lk( fa->_pendingMutex ); if ( fa->_pending.size() == 0 ) break; name = fa->_pending.front(); size = fa->_pendingSize[ name ]; } string tmp; long fd = 0; try { log() << "allocating new datafile " << name << ", filling with zeroes..." << endl; boost::filesystem::path parent = ensureParentDirCreated(name); tmp = fa->makeTempFileName( parent ); ensureParentDirCreated(tmp); #if defined(_WIN32) fd = _open( tmp.c_str(), _O_RDWR | _O_CREAT | O_NOATIME, _S_IREAD | _S_IWRITE ); #else fd = open(tmp.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR); #endif if ( fd < 0 ) { log() << "FileAllocator: couldn't create " << name << " (" << tmp << ") " << errnoWithDescription() << endl; uasserted(10439, ""); } #if defined(POSIX_FADV_DONTNEED) if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTNEED) ) { log() << "warning: posix_fadvise fails " << name << " (" << tmp << ") " << errnoWithDescription() << endl; } #endif Timer t; /* make sure the file is the full desired length */ ensureLength( fd , size ); close( fd ); fd = 0; if( rename(tmp.c_str(), name.c_str()) ) { const string& errStr = errnoWithDescription(); const string& errMessage = str::stream() << "error: couldn't rename " << tmp << " to " << name << ' ' << errStr; msgasserted(13653, errMessage); } flushMyDirectory(name); log() << "done allocating datafile " << name << ", " << "size: " << size/1024/1024 << "MB, " << " took " << ((double)t.millis())/1000.0 << " secs" << endl; // no longer in a failed state. allow new writers. fa->_failed = false; } catch ( const std::exception& e ) { log() << "error: failed to allocate new file: " << name << " size: " << size << ' ' << e.what() << ". will try again in 10 seconds" << endl; if ( fd > 0 ) close( fd ); try { if ( ! tmp.empty() ) boost::filesystem::remove( tmp ); boost::filesystem::remove( name ); } catch ( const std::exception& e ) { log() << "error removing files: " << e.what() << endl; } scoped_lock lk( fa->_pendingMutex ); fa->_failed = true; // not erasing from pending fa->_pendingUpdated.notify_all(); sleepsecs(10); continue; } { scoped_lock lk( fa->_pendingMutex ); fa->_pendingSize.erase( name ); fa->_pending.pop_front(); fa->_pendingUpdated.notify_all(); } } } }