diff options
author | Benety Goh <benety@mongodb.com> | 2014-12-29 16:47:59 -0500 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2015-01-05 15:52:47 -0500 |
commit | d9ce31ea2237d4aa78656fed785e7e5b91c93843 (patch) | |
tree | fafb16c58e74b57fdb3387ea51a98f2d029c8369 | |
parent | 9bfa0cc0f41dc8d425263cbf841f62b3e9d484da (diff) | |
download | mongo-d9ce31ea2237d4aa78656fed785e7e5b91c93843.tar.gz |
SERVER-16677 added platform-dependent class to management creation/locking of mongod.lock in data directory.
-rw-r--r-- | src/mongo/db/storage/SConscript | 18 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_lock_file.h | 95 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_lock_file_posix.cpp | 192 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_lock_file_test.cpp | 173 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_lock_file_win.cpp | 190 |
5 files changed, 668 insertions, 0 deletions
diff --git a/src/mongo/db/storage/SConscript b/src/mongo/db/storage/SConscript index 7210c44f420..aec1069cf09 100644 --- a/src/mongo/db/storage/SConscript +++ b/src/mongo/db/storage/SConscript @@ -81,6 +81,24 @@ env.Library( ) env.Library( + target='storage_engine_lock_file', + source=[ + 'storage_engine_lock_file_${OS_FAMILY}.cpp', + ], + LIBDEPS=[ + ] + ) + +env.CppUnitTest( + target= 'storage_engine_lock_file_test', + source = 'storage_engine_lock_file_test.cpp', + LIBDEPS=[ + 'storage_engine_lock_file', + '$BUILD_DIR/mongo/mongocommon', + ], +) + +env.Library( target='storage_engine_metadata', source=[ 'storage_engine_metadata.cpp', diff --git a/src/mongo/db/storage/storage_engine_lock_file.h b/src/mongo/db/storage/storage_engine_lock_file.h new file mode 100644 index 00000000000..b28ccc29823 --- /dev/null +++ b/src/mongo/db/storage/storage_engine_lock_file.h @@ -0,0 +1,95 @@ +/** + * Copyright (C) 2014 MongoDB 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/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include <boost/scoped_ptr.hpp> +#include <string> + +#include "mongo/base/disallow_copying.h" +#include "mongo/base/status.h" + +namespace mongo { + + class StorageEngineLockFile { + MONGO_DISALLOW_COPYING(StorageEngineLockFile); + public: + + /** + * Checks existing lock file, if present, to see if it contains data from a previous + * unclean shutdown. A clean shutdown should have produced a zero length lock file. + * Uses open() to read existing lock file or create new file. + * Uses boost::filesystem to check lock file so may throw boost::exception. + */ + StorageEngineLockFile(const std::string& dbpath); + + virtual ~StorageEngineLockFile(); + + /** + * Returns the path to the lock file. + */ + std::string getFilespec() const; + + /** + * Returns true if lock file was not zeroed out due to previous unclean shutdown. + * This state is evaluated at object initialization to allow storage engine + * to make decisions on recovery based on this information after open() has been called. + */ + bool createdByUncleanShutdown() const; + + /** + * Opens and locks 'mongod.lock' in 'dbpath' directory. + */ + Status open(); + + /** + * Closes lock file handles. + */ + void close(); + + /** + * Writes current process ID to file. + * Fails if lock file has not been opened. + */ + Status writePid(); + + /** + * Truncates file contents and releases file locks. + */ + void clearPidAndUnlock(); + + private: + std::string _dbpath; + std::string _filespec; + bool _uncleanShutdown; + + class LockFileHandle; + boost::scoped_ptr<LockFileHandle> _lockFileHandle; + }; + +} // namespace mongo diff --git a/src/mongo/db/storage/storage_engine_lock_file_posix.cpp b/src/mongo/db/storage/storage_engine_lock_file_posix.cpp new file mode 100644 index 00000000000..126c53ec4c8 --- /dev/null +++ b/src/mongo/db/storage/storage_engine_lock_file_posix.cpp @@ -0,0 +1,192 @@ +/** + * Copyright (C) 2014 MongoDB 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/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage + +#include "mongo/platform/basic.h" + +#include "mongo/db/storage/storage_engine_lock_file.h" + +#include <boost/filesystem.hpp> +#include <fcntl.h> +#include <ostream> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <sstream> + +#include "mongo/platform/process_id.h" +#include "mongo/util/log.h" +#include "mongo/util/paths.h" +#include "mongo/util/mongoutils/str.h" + +namespace mongo { + +namespace { + + const std::string kLockFileBasename = "mongod.lock"; + +} // namespace + + class StorageEngineLockFile::LockFileHandle { + public: + static const int kInvalidFd = -1; + LockFileHandle() : _fd(kInvalidFd) { } + bool isValid() const { return _fd != kInvalidFd; } + void clear() { _fd = kInvalidFd; } + int _fd; + }; + + StorageEngineLockFile::StorageEngineLockFile(const std::string& dbpath) + : _dbpath(dbpath), + _filespec((boost::filesystem::path(_dbpath) / kLockFileBasename).string()), + _uncleanShutdown(boost::filesystem::exists(_filespec) && + boost::filesystem::file_size(_filespec) > 0), + _lockFileHandle(new LockFileHandle()) { + } + + StorageEngineLockFile::~StorageEngineLockFile() { } + + std::string StorageEngineLockFile::getFilespec() const { + return _filespec; + } + + bool StorageEngineLockFile::createdByUncleanShutdown() const { + return _uncleanShutdown; + } + + Status StorageEngineLockFile::open() { + try { + if (!boost::filesystem::exists(_dbpath)) { + return Status(ErrorCodes::NonExistentPath, str::stream() + << "Data directory " << _dbpath << " not found."); + } + } + catch (const std::exception& ex) { + return Status(ErrorCodes::UnknownError, str::stream() + << "Unable to check existence of data directory " + << _dbpath << ": " << ex.what()); + } + + int lockFile = ::open(_filespec.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); + if (lockFile <= 0) { + int errorcode = errno; + return Status(ErrorCodes::DBPathInUse, str::stream() + << "Unable to create/open lock file: " + << _filespec << ' ' << errnoWithDescription(errorcode) + << " Is a mongod instance already running?"); + } +#if !defined(__sunos__) + int ret = ::flock(lockFile, LOCK_EX | LOCK_NB); +#else + struct flock fileLockInfo = {0}; + fileLockInfo.l_type = F_WRLCK; + fileLockInfo.l_whence = SEEK_SET; + int ret = ::fcntl(lockFile, F_SETLK, &fileLockInfo); +#endif // !defined(__sunos__) + if (ret != 0) { + int errorcode = errno; + ::close(lockFile); + return Status(ErrorCodes::DBPathInUse, str::stream() + << "Unable to lock file: " + << _filespec << ' ' << errnoWithDescription(errorcode) + << ". Is a mongod instance already running?"); + } + _lockFileHandle->_fd = lockFile; + return Status::OK(); + } + + void StorageEngineLockFile::close() { + if (!_lockFileHandle->isValid()) { + return; + } + ::close(_lockFileHandle->_fd); + _lockFileHandle->clear(); + } + + Status StorageEngineLockFile::writePid() { + if (!_lockFileHandle->isValid()) { + return Status(ErrorCodes::FileNotOpen, str::stream() + << "Unable to write process ID to " << _filespec + << " because file has not been opened."); + } + + if (::ftruncate(_lockFileHandle->_fd, 0)) { + int errorcode = errno; + return Status(ErrorCodes::FileStreamFailed, str::stream() + << errnoWithDescription(errorcode)); + } + + ProcessId pid = ProcessId::getCurrent(); + std::stringstream ss; + ss << pid << std::endl; + std::string pidStr = ss.str(); + int bytesWritten = ::write(_lockFileHandle->_fd, pidStr.c_str(), pidStr.size()); + if (bytesWritten < 0) { + int errorcode = errno; + return Status(ErrorCodes::FileStreamFailed, str::stream() + << "Unable to write process id " << pid.toString() << " to file: " + << _filespec << ' ' << errnoWithDescription(errorcode)); + + } + else if (bytesWritten == 0) { + return Status(ErrorCodes::FileStreamFailed, str::stream() + << "Unable to write process id " << pid.toString() << " to file: " + << _filespec << " no data written."); + } + + ::fsync(_lockFileHandle->_fd); + flushMyDirectory(_filespec); + + return Status::OK(); + } + + void StorageEngineLockFile::clearPidAndUnlock() { + if (!_lockFileHandle->isValid()) { + return; + } + log() << "shutdown: removing fs lock..."; + // This ought to be an unlink(), but Eliot says the last + // time that was attempted, there was a race condition + // with acquirePathLock(). + if(::ftruncate(_lockFileHandle->_fd, 0)) { + int errorcode = errno; + log() << "couldn't remove fs lock " << errnoWithDescription(errorcode); + } +#if !defined(__sunos__) + ::flock(_lockFileHandle->_fd, LOCK_UN); +#else + struct flock fileLockInfo = {0}; + fileLockInfo.l_type = F_UNLCK; + fileLockInfo.l_whence = SEEK_SET; + ::fcntl(_lockFileHandle->_fd, F_SETLK, &fileLockInfo); +#endif // !defined(__sunos__) + } + +} // namespace mongo diff --git a/src/mongo/db/storage/storage_engine_lock_file_test.cpp b/src/mongo/db/storage/storage_engine_lock_file_test.cpp new file mode 100644 index 00000000000..2ca432d0d71 --- /dev/null +++ b/src/mongo/db/storage/storage_engine_lock_file_test.cpp @@ -0,0 +1,173 @@ +/** + * Copyright 2014 MongoDB 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/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include <boost/filesystem.hpp> +#include <boost/scoped_ptr.hpp> +#include <fstream> +#include <ostream> + +#include "mongo/db/storage/storage_engine_lock_file.h" +#include "mongo/platform/process_id.h" +#include "mongo/unittest/temp_dir.h" +#include "mongo/unittest/unittest.h" + +namespace { + + using std::string; + using mongo::unittest::TempDir; + + using namespace mongo; + + TEST(StorageEngineLockFileTest, UncleanShutdownNoExistingFile) { + TempDir tempDir("StorageEngineLockFileTest_UncleanShutdownNoExistingFile"); + StorageEngineLockFile lockFile(tempDir.path()); + ASSERT_FALSE(lockFile.createdByUncleanShutdown()); + } + + TEST(StorageEngineLockFileTest, UncleanShutdownEmptyExistingFile) { + TempDir tempDir("StorageEngineLockFileTest_UncleanShutdownEmptyExistingFile"); + { + std::string filename(tempDir.path() + "/mongod.lock"); + std::ofstream(filename.c_str()); + } + StorageEngineLockFile lockFile(tempDir.path()); + ASSERT_FALSE(lockFile.createdByUncleanShutdown()); + } + + TEST(StorageEngineLockFileTest, UncleanShutdownNonEmptyExistingFile) { + TempDir tempDir("StorageEngineLockFileTest_UncleanShutdownNonEmptyExistingFile"); + { + std::string filename(tempDir.path() + "/mongod.lock"); + std::ofstream ofs(filename.c_str()); + ofs << 12345 << std::endl; + } + StorageEngineLockFile lockFile(tempDir.path()); + ASSERT_TRUE(lockFile.createdByUncleanShutdown()); + } + + TEST(StorageEngineLockFileTest, OpenInvalidDirectory) { + StorageEngineLockFile lockFile("no_such_directory"); + ASSERT_EQUALS((boost::filesystem::path("no_such_directory") / "mongod.lock").string(), + lockFile.getFilespec()); + Status status = lockFile.open(); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::NonExistentPath, status.code()); + } + + // Cause ::open() to fail by providing a regular file instead of a directory for 'dbpath'. + TEST(StorageEngineLockFileTest, OpenInvalidFilename) { + TempDir tempDir("StorageEngineLockFileTest_OpenInvalidFilename"); + std::string filename(tempDir.path() + "/some_file"); + std::ofstream(filename.c_str()); + StorageEngineLockFile lockFile(filename); + Status status = lockFile.open(); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::DBPathInUse, status.code()); + } + + TEST(StorageEngineLockFileTest, OpenNoExistingLockFile) { + TempDir tempDir("StorageEngineLockFileTest_OpenNoExistingLockFile"); + StorageEngineLockFile lockFile(tempDir.path()); + ASSERT_OK(lockFile.open()); + lockFile.close(); + } + + TEST(StorageEngineLockFileTest, OpenEmptyLockFile) { + TempDir tempDir("StorageEngineLockFileTest_OpenEmptyLockFile"); + StorageEngineLockFile lockFile(tempDir.path()); + std::string filename(lockFile.getFilespec()); + std::ofstream(filename.c_str()); + ASSERT_OK(lockFile.open()); + lockFile.close(); + } + + TEST(StorageEngineLockFileTest, WritePidFileNotOpened) { + TempDir tempDir("StorageEngineLockFileTest_WritePidFileNotOpened"); + StorageEngineLockFile lockFile(tempDir.path()); + Status status = lockFile.writePid(); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::FileNotOpen, status.code()); + } + + TEST(StorageEngineLockFileTest, WritePidFileOpened) { + TempDir tempDir("StorageEngineLockFileTest_WritePidFileOpened"); + StorageEngineLockFile lockFile(tempDir.path()); + ASSERT_OK(lockFile.open()); + ASSERT_OK(lockFile.writePid()); + lockFile.close(); + + // Read PID from lock file. + std::string filename(lockFile.getFilespec()); + std::ifstream ifs(filename.c_str()); + int64_t pidFromLockFile = 0; + ASSERT_TRUE(ifs >> pidFromLockFile); + ASSERT_EQUALS(ProcessId::getCurrent().asInt64(), pidFromLockFile); + } + + // Existing data in lock file must be removed before writing process ID. + TEST(StorageEngineLockFileTest, WritePidTruncateExistingFile) { + TempDir tempDir("StorageEngineLockFileTest_WritePidTruncateExistingFile"); + StorageEngineLockFile lockFile(tempDir.path()); + { + std::string filename(tempDir.path() + "/mongod.lock"); + std::ofstream ofs(filename.c_str()); + std::string currentPidStr = ProcessId::getCurrent().toString(); + ASSERT_FALSE(currentPidStr.empty()); + ofs << std::string(currentPidStr.size() * 100, 'X') << std::endl; + } + ASSERT_OK(lockFile.open()); + ASSERT_OK(lockFile.writePid()); + lockFile.close(); + + // Read PID from lock file. + std::string filename(lockFile.getFilespec()); + std::ifstream ifs(filename.c_str()); + int64_t pidFromLockFile = 0; + ASSERT_TRUE(ifs >> pidFromLockFile); + ASSERT_EQUALS(ProcessId::getCurrent().asInt64(), pidFromLockFile); + + // There should not be any data in the file after the process ID. + std::string extraData; + ASSERT_FALSE(ifs >> extraData); + } + + TEST(StorageEngineLockFileTest, ClearPidAndUnlock) { + TempDir tempDir("StorageEngineLockFileTest_ClearPidAndUnlock"); + StorageEngineLockFile lockFile(tempDir.path()); + ASSERT_OK(lockFile.open()); + ASSERT_OK(lockFile.writePid()); + + // Clear lock file contents. + lockFile.clearPidAndUnlock(); + ASSERT_TRUE(boost::filesystem::exists(lockFile.getFilespec())); + ASSERT_EQUALS(0U, boost::filesystem::file_size(lockFile.getFilespec())); + } + +} // namespace diff --git a/src/mongo/db/storage/storage_engine_lock_file_win.cpp b/src/mongo/db/storage/storage_engine_lock_file_win.cpp new file mode 100644 index 00000000000..41fc74ea736 --- /dev/null +++ b/src/mongo/db/storage/storage_engine_lock_file_win.cpp @@ -0,0 +1,190 @@ +/** + * Copyright (C) 2014 MongoDB 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/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage + +#include "mongo/platform/basic.h" + +#include "mongo/db/storage/storage_engine_lock_file.h" + +#include <boost/filesystem.hpp> +#include <io.h> +#include <ostream> +#include <sstream> + +#include "mongo/platform/process_id.h" +#include "mongo/util/log.h" +#include "mongo/util/mongoutils/str.h" + +namespace mongo { + +namespace { + + const std::string kLockFileBasename = "mongod.lock"; + + Status _truncateFile(HANDLE handle) { + invariant(handle != INVALID_HANDLE_VALUE); + + LARGE_INTEGER largeint; + largeint.QuadPart = 0; + if (::SetFilePointerEx(handle, largeint, NULL, FILE_BEGIN) == FALSE) { + int errorcode = GetLastError(); + return Status(ErrorCodes::FileStreamFailed, str::stream() + << "Unable to truncate lock file (SetFilePointerEx failed) " + << errnoWithDescription(errorcode)); + } + + if (::SetEndOfFile(handle) == FALSE) { + int errorcode = GetLastError(); + return Status(ErrorCodes::FileStreamFailed, str::stream() + << "Unable to truncate lock file (SetEndOfFile failed) " + << errnoWithDescription(errorcode)); + } + + return Status::OK(); + } + +} // namespace + + class StorageEngineLockFile::LockFileHandle { + public: + LockFileHandle() : _handle(INVALID_HANDLE_VALUE) { } + bool isValid() const { return _handle != INVALID_HANDLE_VALUE; } + void clear() { _handle = INVALID_HANDLE_VALUE; } + HANDLE _handle; + }; + + StorageEngineLockFile::StorageEngineLockFile(const std::string& dbpath) + : _dbpath(dbpath), + _filespec((boost::filesystem::path(_dbpath) / kLockFileBasename).string()), + _uncleanShutdown(boost::filesystem::exists(_filespec) && + boost::filesystem::file_size(_filespec) > 0), + _lockFileHandle(new LockFileHandle()) { + } + + StorageEngineLockFile::~StorageEngineLockFile() { } + + std::string StorageEngineLockFile::getFilespec() const { + return _filespec; + } + + bool StorageEngineLockFile::createdByUncleanShutdown() const { + return _uncleanShutdown; + } + + Status StorageEngineLockFile::open() { + try { + if (!boost::filesystem::exists(_dbpath)) { + return Status(ErrorCodes::NonExistentPath, str::stream() + << "Data directory " << _dbpath << " not found."); + } + } + catch (const std::exception& ex) { + return Status(ErrorCodes::UnknownError, str::stream() + << "Unable to check existence of data directory " + << _dbpath << ": " << ex.what()); + } + + HANDLE lockFileHandle = CreateFileA(_filespec.c_str(), GENERIC_READ | GENERIC_WRITE, + 0 /* do not allow anyone else access */, NULL, + OPEN_ALWAYS /* success if fh can open */, 0, NULL); + + if (lockFileHandle == INVALID_HANDLE_VALUE) { + int errorcode = GetLastError(); + return Status(ErrorCodes::DBPathInUse, str::stream() + << "Unable to create/open lock file: " << _filespec << ' ' + << errnoWithDescription(errorcode) + << ". Is a mongod instance already running?"); + } + _lockFileHandle->_handle = lockFileHandle; + return Status::OK(); + } + + void StorageEngineLockFile::close() { + if (!_lockFileHandle->isValid()) { + return; + } + CloseHandle(_lockFileHandle->_handle); + _lockFileHandle->clear(); + } + + Status StorageEngineLockFile::writePid() { + if (!_lockFileHandle->isValid()) { + return Status(ErrorCodes::FileNotOpen, str::stream() + << "Unable to write process ID to " << _filespec + << " because file has not been opened."); + } + + Status status = _truncateFile(_lockFileHandle->_handle); + if (!status.isOK()) { + return status; + } + + ProcessId pid = ProcessId::getCurrent(); + std::stringstream ss; + ss << pid << std::endl; + std::string pidStr = ss.str(); + DWORD bytesWritten = 0; + if (::WriteFile(_lockFileHandle->_handle, + static_cast<LPCVOID>(pidStr.c_str()), + static_cast<DWORD>(pidStr.size()), + &bytesWritten, + NULL) == FALSE) { + int errorcode = GetLastError(); + return Status(ErrorCodes::FileStreamFailed, str::stream() + << "Unable to write process id " << pid.toString() << " to file: " + << _filespec << ' ' << errnoWithDescription(errorcode)); + } + else if (bytesWritten == 0) { + return Status(ErrorCodes::FileStreamFailed, str::stream() + << "Unable to write process id " << pid.toString() << " to file: " + << _filespec << " no data written."); + } + + ::FlushFileBuffers(_lockFileHandle->_handle); + + return Status::OK(); + } + + void StorageEngineLockFile::clearPidAndUnlock() { + if (!_lockFileHandle->isValid()) { + return; + } + log() << "shutdown: removing fs lock..."; + // This ought to be an unlink(), but Eliot says the last + // time that was attempted, there was a race condition + // with acquirePathLock(). + Status status = _truncateFile(_lockFileHandle->_handle); + if (!status.isOK()) { + log() << "couldn't remove fs lock " << status.toString(); + } + CloseHandle(_lockFileHandle->_handle); + _lockFileHandle->clear(); + } + +} // namespace mongo |