long long MmapV1ExtentManager::fileSize() const { long long size = 0; for (int n = 0; boost::filesystem::exists(_fileName(n)); n++) { size += boost::filesystem::file_size(_fileName(n)); } return size; }
DataFile* MmapV1ExtentManager::_addAFile(OperationContext* txn, int sizeNeeded, bool preallocateNextFile) { // Database must be stable and we need to be in some sort of an update operation in order // to add a new file. invariant(txn->lockState()->isDbLockedForMode(_dbname, MODE_IX)); const int allocFileId = _files.size(); int minSize = 0; if (allocFileId > 0) { // Make the next file at least as large as the previous minSize = _files[allocFileId - 1]->getHeader()->fileLength; } if (minSize < sizeNeeded + DataFileHeader::HeaderSize) { minSize = sizeNeeded + DataFileHeader::HeaderSize; } { unique_ptr<DataFile> allocFile(new DataFile(allocFileId)); const string allocFileName = _fileName(allocFileId).string(); Timer t; allocFile->open(txn, allocFileName.c_str(), minSize, false); if (t.seconds() > 1) { log() << "MmapV1ExtentManager took " << t.seconds() << " seconds to open: " << allocFileName; } // It's all good _files.push_back(allocFile.release()); } // Preallocate is asynchronous if (preallocateNextFile) { unique_ptr<DataFile> nextFile(new DataFile(allocFileId + 1)); const string nextFileName = _fileName(allocFileId + 1).string(); nextFile->open(txn, nextFileName.c_str(), minSize, false); } // Returns the last file added return _files[allocFileId]; }
Status MmapV1ExtentManager::init(OperationContext* txn) { invariant(_files.empty()); for (int n = 0; n < DiskLoc::MaxFiles; n++) { const boost::filesystem::path fullName = _fileName(n); if (!boost::filesystem::exists(fullName)) { break; } const std::string fullNameString = fullName.string(); { // If the file is uninitialized we exit the loop because it is just prealloced. We // do this on a bare File object rather than using the DataFile because closing a // DataFile triggers dur::closingFileNotification() which is fatal if there are any // pending writes. Therefore we must only open files that we know we want to keep. File preview; preview.open(fullNameString.c_str(), /*readOnly*/ true); invariant(preview.is_open()); // File can't be initialized if too small. if (preview.len() < sizeof(DataFileHeader)) { break; } // This is the equivalent of DataFileHeader::uninitialized(). int version; preview.read(0, reinterpret_cast<char*>(&version), sizeof(version)); invariant(!preview.bad()); if (version == 0) { break; } } unique_ptr<DataFile> df(new DataFile(n)); Status s = df->openExisting(fullNameString.c_str()); if (!s.isOK()) { return s; } invariant(!df->getHeader()->uninitialized()); // We only checkUpgrade on files that we are keeping, not preallocs. df->getHeader()->checkUpgrade(txn); _files.push_back( df.release() ); } // If this is a new database being created, instantiate the first file and one extent so // we can have a coherent database. if (_files.empty()) { WriteUnitOfWork wuow(txn); _createExtent(txn, initialSize(128), false); wuow.commit(); // Commit the journal and all changes to disk so that even if exceptions occur during // subsequent initialization, we won't have uncommited changes during file close. getDur().commitNow(txn); } return Status::OK(); }
status_t SharedMemory :: SetArea(const char * keyString, uint32 createSize, bool returnLocked) { UnsetArea(); // make sure everything is deallocated to start with #if defined(MUSCLE_FAKE_SHARED_MEMORY) if (createSize > 0) { _area = muscleAlloc(createSize); if (_area) { memset(_area, 0, createSize); _areaName = keyString; _areaSize = createSize; _isCreatedLocally = true; _isLocked = returnLocked; _isLockedReadOnly = false; return B_NO_ERROR; } else WARN_OUT_OF_MEMORY; } #elif defined(WIN32) char buf[64]; if (keyString == NULL) { muscleSprintf(buf, INT32_FORMAT_SPEC, GetTickCount()); // No user-supplied name? We'll pick an arbitrary name then keyString = buf; } _areaName = keyString; // For windows we only use a Mutex, because even a Windows semaphore isn't enough to // do shared read locking. When I figure out how to do interprocess shared read locking // under Windows I will implement that, but for now it's always exclusive-locking. :^( _mutex = CreateMutexA(NULL, true, (_areaName+"__mutex")()); if (_mutex != NULL) { bool ok = true; if (GetLastError() == ERROR_ALREADY_EXISTS) ok = (LockAreaReadWrite() == B_NO_ERROR); else { // We created it in our CreateMutex() call, and it's already locked for us _isLocked = true; _isLockedReadOnly = false; } if (ok) { char buf[MAX_PATH]; if (GetTempPathA(sizeof(buf), buf) > 0) { _fileName = _areaName.Prepend(buf)+"__file"; _file = CreateFileA(_fileName(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH|FILE_FLAG_RANDOM_ACCESS, NULL); if (_file != INVALID_HANDLE_VALUE) { _isCreatedLocally = (GetLastError() != ERROR_ALREADY_EXISTS); if (createSize == 0) createSize = GetFileSize(_file, NULL); _areaSize = createSize; // assume the file will be resized automagically for us if (_areaSize > 0) { _map = CreateFileMappingA(_file, NULL, PAGE_READWRITE, 0, createSize, (_areaName+"__map")()); if (_map) { _area = MapViewOfFile(_map, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (_area) { if (returnLocked == false) UnlockArea(); return B_NO_ERROR; } } } } } } } #else key_t requestedKey = IPC_PRIVATE; if (keyString) { requestedKey = (key_t) CalculateHashCode(keyString, (uint32)strlen(keyString)); if (requestedKey == IPC_PRIVATE) requestedKey++; _areaName = keyString; } DECLARE_SEMCTL_ARG(semopts); const int permissionBits = 0777; // Try to create a new semaphore to control access to our area _semID = semget(requestedKey, 1, IPC_CREAT|IPC_EXCL|permissionBits); if (_semID >= 0) { // race condition here!? semopts.val = LARGEST_SEMAPHORE_DELTA; if (semctl(_semID, 0, SETVAL, semopts) < 0) _semID = -1; // oops! } else _semID = semget(requestedKey, 1, permissionBits); // Couldn't create? then get the existing one if (_semID >= 0) { _key = requestedKey; // If we requested a private key, we still need to know the actual key value if (_key == IPC_PRIVATE) { struct semid_ds semInfo = {}; // the braces zero-initialize the struct for us, to keep clang++SA happy semopts.buf = &semInfo; if (semctl(_semID, 0, IPC_STAT, semopts) == 0) { # ifdef __linux__ _key = semInfo.sem_perm.__key; // Mac os-x leopard uses '_key' by default. Both Tiger and Leopard may use _key if the following condition is true, otherwise they use 'key'. # elif (defined(__APPLE__) && (defined(__POSIX_C_SOURCE) || defined(__LP64__))) || __DARWIN_UNIX03 _key = semInfo.sem_perm._key; # else _key = semInfo.sem_perm.key; # endif } _areaName = "private"; // sorry, it's the best I can do short of figuring out how to invert the hash function! } if ((_key != IPC_PRIVATE)&&(LockAreaReadWrite() == B_NO_ERROR)) { _areaID = shmget(_key, 0, permissionBits); if ((_areaID < 0)&&(createSize > 0)) { _areaID = shmget(_key, createSize, IPC_CREAT|IPC_EXCL|permissionBits); _isCreatedLocally = true; } if (_areaID >= 0) { _area = shmat(_areaID, NULL, 0); if ((_area)&&(_area != ((void *)-1))) // FogBugz #7294 { // Now get the stats on our area struct shmid_ds buf; if (shmctl(_areaID, IPC_STAT, &buf) == 0) { _areaSize = (uint32) buf.shm_segsz; if (returnLocked == false) UnlockArea(); return B_NO_ERROR; } } } } } #endif UnsetArea(); // oops, roll back everything! return B_ERROR; }