diff --git a/arangod/VocBase/datafile.cpp b/arangod/VocBase/datafile.cpp index e8c1208c1f..20d0d828fa 100644 --- a/arangod/VocBase/datafile.cpp +++ b/arangod/VocBase/datafile.cpp @@ -487,6 +487,22 @@ void TRI_datafile_t::dontNeed() { TRI_MMFileAdvise(_data, _maximalSize, TRI_MADVISE_DONTNEED); } +void TRI_datafile_t::readOnly() { + int res = TRI_ProtectMMFile(_data, _maximalSize, PROT_READ, _fd); + + if (res == TRI_ERROR_NO_ERROR) { + _state = TRI_DF_STATE_READ; + } +} + +void TRI_datafile_t::readWrite() { + int res = TRI_ProtectMMFile(_data, _maximalSize, PROT_READ | PROT_WRITE, _fd); + + if (res == TRI_ERROR_NO_ERROR) { + _state = TRI_DF_STATE_WRITE; + } +} + int TRI_datafile_t::lockInMemory() { TRI_ASSERT(!_lockedInMemory); int res = TRI_MMFileLock(_data, _initSize); @@ -788,7 +804,10 @@ int TRI_datafile_t::seal() { // everything is now synced _synced = _written; - TRI_ProtectMMFile(_data, _maximalSize, PROT_READ, _fd); + // intentionally ignore return value of protection here because this call + // would only restrict further file accesses (which is not required + // for ArangoDB to work) + readOnly(); // seal datafile if (ok) { @@ -817,16 +836,13 @@ int TRI_datafile_t::truncate(std::string const& path, TRI_voc_size_t position) { // this function must not be called for non-physical datafiles TRI_ASSERT(!path.empty()); - TRI_datafile_t* datafile = TRI_datafile_t::openHelper(path, true); + std::unique_ptr datafile(TRI_datafile_t::openHelper(path, true)); if (datafile == nullptr) { return TRI_ERROR_ARANGO_DATAFILE_UNREADABLE; } - int res = datafile->truncateAndSeal(position); - delete datafile; - - return res; + return datafile->truncateAndSeal(position); } /// @brief try to repair a datafile @@ -841,12 +857,9 @@ bool TRI_datafile_t::tryRepair(std::string const& path) { } // set to read/write access - TRI_ProtectMMFile(datafile->_data, datafile->maximalSize(), - PROT_READ | PROT_WRITE, datafile->fd()); + datafile->readWrite(); - bool result = datafile->tryRepair(); - - return result; + return datafile->tryRepair(); } //////////////////////////////////////////////////////////////////////////////// @@ -1169,6 +1182,7 @@ int TRI_datafile_t::truncateAndSeal(TRI_voc_size_t position) { bool TRI_datafile_t::check(bool ignoreFailures) { // this function must not be called for non-physical datafiles TRI_ASSERT(isPhysical()); + LOG(TRACE) << "checking markers in datafile '" << getName() << "'"; char const* ptr = _data; char const* end = _data + _currentSize; @@ -1717,8 +1731,9 @@ TRI_datafile_t* TRI_datafile_t::open(std::string const& filename, bool ignoreFai // change to read-write if no footer has been found if (!datafile->_isSealed) { - datafile->_state = TRI_DF_STATE_WRITE; - TRI_ProtectMMFile(datafile->_data, datafile->_maximalSize, PROT_READ | PROT_WRITE, datafile->_fd); + datafile->readWrite(); + } else { + datafile->readOnly(); } // Advise on sequential use: @@ -1842,7 +1857,7 @@ TRI_datafile_t* TRI_datafile_t::openHelper(std::string const& filename, bool ign } // map datafile into memory - res = TRI_MMFile(0, size, PROT_READ, MAP_SHARED, fd, &mmHandle, 0, &data); + res = TRI_MMFile(0, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, &mmHandle, 0, &data); if (res != TRI_ERROR_NO_ERROR) { TRI_set_errno(res); diff --git a/arangod/VocBase/datafile.h b/arangod/VocBase/datafile.h index 4c201272cc..48509d9150 100644 --- a/arangod/VocBase/datafile.h +++ b/arangod/VocBase/datafile.h @@ -235,6 +235,8 @@ struct TRI_datafile_t { void randomAccess(); void willNeed(); void dontNeed(); + void readOnly(); + void readWrite(); int lockInMemory(); int unlockFromMemory(); diff --git a/lib/Basics/memory-map-posix.cpp b/lib/Basics/memory-map-posix.cpp index 2ecfdc47db..7cab4932ae 100644 --- a/lib/Basics/memory-map-posix.cpp +++ b/lib/Basics/memory-map-posix.cpp @@ -32,6 +32,34 @@ using namespace arangodb; +namespace { +static std::string flagify(int flags) { + std::string result; + + int const remain = flags & (PROT_READ | PROT_WRITE | PROT_EXEC); + + if (remain & PROT_READ) { + result.append("read"); + } + + if (remain & PROT_WRITE) { + if (!result.empty()) { + result.push_back(','); + } + result.append("write"); + } + + if (remain & PROT_EXEC) { + if (!result.empty()) { + result.push_back(','); + } + result.append("exec"); + } + + return result; +} +} + //////////////////////////////////////////////////////////////////////////////// // @brief flush memory mapped file to disk //////////////////////////////////////////////////////////////////////////////// @@ -91,7 +119,7 @@ int TRI_MMFile(void* memoryAddress, size_t numOfBytesToInitialize, if (*result != MAP_FAILED) { TRI_ASSERT(*result != nullptr); - LOG_TOPIC(DEBUG, Logger::MMAP) << "memory-mapped range " << Logger::RANGE(*result, numOfBytesToInitialize) << ", file-descriptor " << fileDescriptor; + LOG_TOPIC(DEBUG, Logger::MMAP) << "memory-mapped range " << Logger::RANGE(*result, numOfBytesToInitialize) << ", file-descriptor " << fileDescriptor << ", flags: " << flagify(flags); return TRI_ERROR_NO_ERROR; } @@ -100,6 +128,8 @@ int TRI_MMFile(void* memoryAddress, size_t numOfBytesToInitialize, LOG_TOPIC(DEBUG, Logger::MMAP) << "out of memory in mmap"; return TRI_ERROR_OUT_OF_MEMORY_MMAP; + } else { + LOG_TOPIC(WARN, Logger::MMAP) << "memory-mapping failed for range " << Logger::RANGE(*result, numOfBytesToInitialize) << ", file-descriptor " << fileDescriptor << ", flags: " << flagify(flags); } return TRI_ERROR_SYS_ERROR; @@ -142,10 +172,12 @@ int TRI_ProtectMMFile(void* memoryAddress, size_t numOfBytesToProtect, int res = mprotect(memoryAddress, numOfBytesToProtect, flags); if (res == TRI_ERROR_NO_ERROR) { - LOG_TOPIC(TRACE, Logger::MMAP) << "memory-protecting range " << Logger::RANGE(memoryAddress, numOfBytesToProtect) << ", file-descriptor " << fileDescriptor; + LOG_TOPIC(TRACE, Logger::MMAP) << "memory-protecting range " << Logger::RANGE(memoryAddress, numOfBytesToProtect) << ", file-descriptor " << fileDescriptor << ", flags: " << flagify(flags); return TRI_ERROR_NO_ERROR; } + + LOG_TOPIC(WARN, Logger::MMAP) << "memory-protecting failed for range " << Logger::RANGE(memoryAddress, numOfBytesToProtect) << ", file-descriptor " << fileDescriptor << ", flags: " << flagify(flags); return TRI_ERROR_SYS_ERROR; }