/** * Close the given file. Also updates the InodeFile on disk. */ bool InodeFileStore::closeFile(EntryInfo* entryInfo, FileInode* inode, unsigned accessFlags, unsigned* outNumHardlinks, unsigned* outNumRefs) { // FIXME Bernd: Maybe we should test with a read-lock if the file is in the store at all? SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K bool inStore = false; *outNumHardlinks = 1; // (we're careful here about inodes that are not currently open) InodeMapIter iter = this->inodes.find(inode->getEntryID() ); if(iter != this->inodes.end() ) { // outInode exists *outNumHardlinks = inode->getNumHardlinks(); // Store inode information on disk, they have been set with inode->setDynAttribs() before entryInfo->setInodeInlinedFlag(inode->getIsInlined() ); inode->decNumSessionsAndStore(entryInfo, accessFlags); *outNumRefs = decreaseInodeRefCountUnlocked(iter); inStore = true; } safeLock.unlock(); // U N L O C K return inStore; }
/** * @param disableLoading true to check the in-memory tree only (and don't try to load the * metadata from disk) */ FhgfsOpsErr InodeFileStore::stat(EntryInfo* entryInfo, bool loadFromDisk, StatData& outStatData) { std::string entryID = entryInfo->getEntryID(); FhgfsOpsErr statRes = FhgfsOpsErr_PATHNOTEXISTS; SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K InodeMapIter iter = inodes.find(entryID); if(iter != inodes.end() ) { // inode loaded FileInodeReferencer* fileRefer = iter->second; FileInode* inode = fileRefer->getReferencedObject(); statRes = inode->getStatData(outStatData); safeLock.unlock(); // U N L O C K } else if (loadFromDisk == true) { // not loaded => static stat safeLock.unlock(); // U N L O C K give up the lock, as we don't do anything with the store statRes = FileInode::getStatData(entryInfo, outStatData); } else safeLock.unlock(); // U N L O C K return statRes; }
/** * Note: This works by serializing the original and marking the object unreferencable (exclusive), * so remember to call movingCancel() or movingComplete() * * @param buf target buffer for serialization (only valid if success is returned) * @param bufLen must be at least META_SERBUF_SIZE * @param outUsedBufLen the used bufLen */ FhgfsOpsErr InodeFileStore::moveRemoteBegin(EntryInfo* entryInfo, char* buf, size_t bufLen, size_t* outUsedBufLen) { const char* logContext = "Serialize Inode"; FhgfsOpsErr retVal = FhgfsOpsErr_PATHNOTEXISTS; if(bufLen < META_SERBUF_SIZE) { LogContext(logContext).log(Log_ERR, "Error: Buffer too small!"); return FhgfsOpsErr_INTERNAL; } SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K FileInode* inode; retVal = getUnreferencedInodeUnlocked(entryInfo, &inode); // does not set refCount if (retVal == FhgfsOpsErr_SUCCESS) { /* We got an inode, which is in the map, but is unreferenced. Now we are going to exclusively * lock it. If another thread should try to reference it, it will fail due to this lock. */ *outUsedBufLen = inode->serializeMetaData(buf); inode->setExclusive(true); } safeLock.unlock(); // U N L O C K return retVal; }
/** * Note: remember to call releaseFileInode() * * @param loadFromDisk - true for the per-directory InodeFileStore, false for references * from MetaStore (global map) * @return NULL if no such file exists * * FIXME: Bernd: Does not need writeLock if loadFromDisk=false and nothing found */ FileInode* InodeFileStore::referenceFileInode(EntryInfo* entryInfo, bool loadFromDisk) { SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K FileInode* inode = referenceFileInodeUnlocked(entryInfo, loadFromDisk); safeLock.unlock(); // U N L O C K return inode; }
FhgfsOpsErr InodeFileStore::makeFileInode(FileInode* inode, bool keepInode) { SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K FhgfsOpsErr retVal = makeFileInodeUnlocked(inode, keepInode); safeLock.unlock(); return retVal; }
/** * Insert the existing FileInodeReferencer into the map. * * This is mainly required to move references between stores (per-directory to metaStore) */ bool InodeFileStore::insertReferencer(std::string entryID, FileInodeReferencer* fileRefer) { SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K bool retVal = this->inodes.insert(InodeMapVal(entryID, fileRefer) ).second; safeLock.unlock(); // U N L O C K return retVal; }
bool InodeFileStore::exists(std::string fileID) { SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K bool existsRes = existsUnlocked(fileID); safeLock.unlock(); // U N L O C K return existsRes; }
/** * Note: This does not load any entries, so it will only return the number of already loaded * entries. (Only useful for debugging and statistics probably.) */ size_t InodeFileStore::getSize() { SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K size_t filesSize = inodes.size(); safeLock.unlock(); // U N L O C K return filesSize; }
/** * @param outFile will be set to the unlinked file and the object must then be deleted by the caller * (can be NULL if the caller is not interested in the file) */ FhgfsOpsErr InodeFileStore::unlinkFileInode(EntryInfo* entryInfo, FileInode** outInode) { SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K FhgfsOpsErr delErr = unlinkFileInodeUnlocked(entryInfo, outInode); safeLock.unlock(); // U N L O C K return delErr; }
void DataRequestorStats::waitForShutdown() { SafeMutexLock safeLock(&this->statusMutex); while(DATAREQUESTORSTATSSTATUS_IS_ACTIVE(this->status)) { this->statusChangeCond.wait(&this->statusMutex); } safeLock.unlock(); }
FhgfsOpsErr InodeFileStore::isUnlinkable(EntryInfo* entryInfo, bool loadFromDisk, FileInode** outInode) { SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K FhgfsOpsErr retVal = this->isUnlinkableUnlocked(entryInfo, loadFromDisk, outInode); safeLock.unlock(); return retVal; }
/** * Unlink an overwritten dentry. From this dentry either the #fsid# entry or its inode is left. * * Locking: * We lock everything ourself */ FhgfsOpsErr MetaStore::unlinkOverwrittenEntry(DirInode* parentDir, DirEntry* overWrittenEntry, FileInode** outInode) { SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K SafeRWLock parentLock(&parentDir->rwlock, SafeRWLock_WRITE); FhgfsOpsErr unlinkRes = unlinkOverwrittenEntryUnlocked(parentDir, overWrittenEntry, outInode); parentLock.unlock(); safeLock.unlock(); return unlinkRes; }
/** * check if the given ID is in the store * */ bool InodeFileStore::isInStore(std::string fileID) { bool inStore = false; SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K InodeMapIter iter = inodes.find(fileID); if(iter != inodes.end() ) inStore = true; safeLock.unlock(); // U N L O C K return inStore; }
/** * References a file to be known to already referenced. * Also could be called "referenceReferencedFile" * * Note: remember to call releaseFileInode() * * @param loadFromDisk - true for the per-directory InodeFileStore, false for references * from MetaStore (global map) * @return NULL if no such file exists */ FileInode* InodeFileStore::referenceLoadedFile(std::string entryID) { FileInode* inode = NULL; SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K InodeMapIter iter = this->inodes.find(entryID); if(iter != this->inodes.end() ) { inode = referenceFileInodeMapIterUnlocked(iter, &this->inodes); } safeLock.unlock(); // U N L O C K return inode; }
/** * @return entryID of the old entry */ void InodeFileStore::moveRemoteComplete(std::string entryID) { // moving succeeded => delete original SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K InodeMapIter iter = inodes.find(entryID); if(iter != inodes.end() ) { // file exists FileInodeReferencer* fileRefer = iter->second; delete fileRefer; inodes.erase(entryID); } safeLock.unlock(); // U N L O C K }
/** * @param outNumHardlinks for quick on-close unlink check (may not be NULL!) * @return false if file was not in store at all, true if we found the file in the store */ bool InodeFileStore::releaseFileInode(FileInode* inode) { bool inStore = false; SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K InodeMapIter iter = this->inodes.find(inode->getEntryID() ); if(iter != this->inodes.end() ) { // outInode exists => decrease refCount decreaseInodeRefCountUnlocked(iter); inStore = true; } safeLock.unlock(); // U N L O C K return inStore; }
void MetaStore::moveRemoteFileComplete(DirInode* dir, std::string entryID) { SafeRWLock safeLock(&this->rwlock, SafeRWLock_WRITE); // L O C K if (this->fileStore.isInStore(entryID) ) this->fileStore.moveRemoteComplete(entryID); else { SafeRWLock safeDirLock(&dir->rwlock, SafeRWLock_READ); dir->fileStore.moveRemoteComplete(entryID); safeDirLock.unlock(); } safeLock.unlock(); // U N L O C K }
/** * @param validAttribs SETATTR_CHANGE_...-Flags */ FhgfsOpsErr InodeFileStore::setAttr(EntryInfo* entryInfo, int validAttribs, SettableFileAttribs* attribs) { std::string entryID = entryInfo->getEntryID(); FhgfsOpsErr retVal = FhgfsOpsErr_PATHNOTEXISTS; SafeRWLock safeLock(&rwlock, SafeRWLock_WRITE); // L O C K InodeMapIter iter = inodes.find(entryID); if(iter == inodes.end() ) { // not loaded => load, apply, destroy // Note: A very uncommon code path, as SetAttrMsgEx::setAttr() references the inode first. // FIXME Bernd: Another use case for loadFromEntryInfo(). FileInode* inode = FileInode::createFromEntryInfo(entryInfo); if(inode) { // loaded bool setRes = inode->setAttrData(entryInfo, validAttribs, attribs); retVal = setRes ? FhgfsOpsErr_SUCCESS : FhgfsOpsErr_INTERNAL; delete inode; } } else { // inode loaded FileInodeReferencer* inodeRefer = iter->second; FileInode* inode = inodeRefer->getReferencedObject(); if(!inode->getExclusive() ) { bool setRes = inode->setAttrData(entryInfo, validAttribs, attribs); retVal = setRes ? FhgfsOpsErr_SUCCESS : FhgfsOpsErr_INTERNAL; } } safeLock.unlock(); // U N L O C K return retVal; }
/** * Get the referencer and delete this ID from the map. Mainly used to move the referencer between * Stores. */ FileInodeReferencer* InodeFileStore::getReferencerAndDeleteFromMap(std::string fileID) { FileInodeReferencer* fileRefer = NULL; SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K InodeMapIter iter = this->inodes.find(fileID); if(iter != inodes.end() ) { // exists in map fileRefer = iter->second; this->inodes.erase(iter); } safeLock.unlock(); // U N L O C K return fileRefer; }
/** * Copies (serializes) the original file object to a buffer. * * Note: This works by inserting a temporary placeholder and returning the original, so remember to * call movingComplete() * * @param buf target buffer for serialization * @param bufLen must be at least META_SERBUF_SIZE */ FhgfsOpsErr MetaStore::moveRemoteFileBegin(DirInode* dir, EntryInfo* entryInfo, char* buf, size_t bufLen, size_t* outUsedBufLen) { FhgfsOpsErr retVal = FhgfsOpsErr_INTERNAL; SafeRWLock safeLock(&this->rwlock, SafeRWLock_READ); // L O C K // lock the dir to make sure no renameInSameDir is going on SafeRWLock safeDirLock(&dir->rwlock, SafeRWLock_READ); if (this->fileStore.isInStore(entryInfo->getEntryID() ) ) retVal = this->fileStore.moveRemoteBegin(entryInfo, buf, bufLen, outUsedBufLen); else { retVal = dir->fileStore.moveRemoteBegin(entryInfo, buf, bufLen, outUsedBufLen); } safeDirLock.unlock(); safeLock.unlock(); // U N L O C K return retVal; }
/** * Clears out stale capacity reports, i.e. reports where the target/node is not ONLINE+GOOD * or where the target node is unknown to the targetStateStore (has been unmapped in the * meantime) from the target/nodeCapacityReportMap. * * @param nodeType Selects whether to look at storage targets or metadata nodes. */ void InternodeSyncer::clearStaleCapacityReports(const NodeType nodeType) { TargetStateStore* stateStore = (nodeType == NODETYPE_Meta) ? Program::getApp()->getMetaStateStore() : Program::getApp()->getTargetStateStore(); RWLock* reportsRWLock = (nodeType == NODETYPE_Meta) ? &nodeCapacityReportMapLock : &targetCapacityReportMapLock; TargetCapacityReportMap& capacityReportMap = (nodeType == NODETYPE_Meta) ? nodeCapacityReportMap : targetCapacityReportMap; const CombinedTargetState onlineGoodState( TargetReachabilityState_ONLINE, TargetConsistencyState_GOOD); SafeRWLock safeLock(reportsRWLock, SafeRWLock_WRITE); // L O C K for (TargetCapacityReportMapIter reportIter = capacityReportMap.begin(); reportIter != capacityReportMap.end(); /* iter increment in loop body */ ) { const uint16_t targetID = reportIter->first; CombinedTargetState targetState; bool getStateRes = stateStore->getState(targetID, targetState); if ( !getStateRes || (targetState != onlineGoodState) ) capacityReportMap.erase(reportIter++); else ++reportIter; } safeLock.unlock(); // U N L O C K }
void XMMediaStream::OnPatchStart() { if (IsSource()) { PSafeLockReadWrite safeLock(*this); if (!safeLock.IsLocked()) { return; } // Ensure the code below runs just once. // Also avoid possible race conditions if (hasStarted == true || isTerminated == true) { return; } RTP_DataFrame::PayloadTypes payloadType = mediaFormat.GetPayloadType(); unsigned frameTime = mediaFormat.GetFrameTime(); unsigned framesPerSecond = (unsigned)round((double)OpalMediaFormat::VideoClockRate / (double)frameTime); framesPerSecond = std::min((unsigned)XM_MAX_FPS, framesPerSecond); framesPerSecond = std::max(framesPerSecond, (unsigned)1); unsigned bitrate = mediaFormat.GetBandwidth(); bitrate = std::min(bitrate, XMOpalManager::GetManager()->GetVideoBandwidthLimit(mediaFormat)); unsigned flags = 0; XMCodecIdentifier codecIdentifier = _XMGetMediaFormatCodec(mediaFormat); XMVideoSize videoSize = _XMGetMediaFormatSize(mediaFormat); if (codecIdentifier == XMCodecIdentifier_UnknownCodec || videoSize == XMVideoSize_NoVideo || videoSize == XMVideoSize_Custom) { // Shouldn't actually happen return; } if (codecIdentifier == XMCodecIdentifier_H263) { // If we're sending H.263, we need to know which // format to send. The payload code is submitted in the // flags parameter flags = payloadType; if (payloadType == RTP_DataFrame::H263) { cout << "Sending RFC2190" << endl; } else { cout << "Sending RFC2429" << endl; } } else if (codecIdentifier == XMCodecIdentifier_H264) { unsigned packetizationMode = _XMGetH264PacketizationMode(mediaFormat); if (packetizationMode == XM_H264_PACKETIZATION_MODE_SINGLE_NAL) { // We send only at a limited bitrate to avoid too many // NAL units which are TOO big to fit if (bitrate > 380000) { bitrate = 380000; } } flags = (packetizationMode << 8) + (_XMGetH264Profile(mediaFormat) << 4) + _XMGetH264Level(mediaFormat); } videoTransmitterStream = this; hasStarted = true; dataFrame.SetPayloadSize(0); dataFrame.SetPayloadType(payloadType); unsigned keyFrameInterval = GetKeyFrameInterval(codecIdentifier); _XMStartMediaTransmit(2, codecIdentifier, videoSize, framesPerSecond, bitrate, keyFrameInterval, flags); } }
/** * Simple rename on the same server in the same directory. * * @param outUnlinkInode is the inode of a dirEntry being possibly overwritten (toName already * existed). */ FhgfsOpsErr MetaStore::renameInSameDir(DirInode* parentDir, std::string fromName, std::string toName, FileInode** outUnlinkInode) { const char* logContext = "Rename in dir"; SafeRWLock safeLock(&rwlock, SafeRWLock_READ); // L O C K SafeRWLock fromMutexLock(&parentDir->rwlock, SafeRWLock_WRITE); // L O C K ( F R O M ) FhgfsOpsErr retVal; FhgfsOpsErr unlinkRes; DirEntry* overWrittenEntry = NULL; retVal = performRenameEntryInSameDir(parentDir, fromName, toName, &overWrittenEntry); if (retVal != FhgfsOpsErr_SUCCESS) { fromMutexLock.unlock(); safeLock.unlock(); SAFE_DELETE(overWrittenEntry); return retVal; } EntryInfo unlinkEntryInfo; bool unlinkedWasInlined; if (overWrittenEntry) { std::string parentDirID = parentDir->getID(); overWrittenEntry->getEntryInfo(parentDirID, 0, &unlinkEntryInfo); unlinkedWasInlined = overWrittenEntry->getIsInodeInlined(); unlinkRes = unlinkOverwrittenEntryUnlocked(parentDir, overWrittenEntry, outUnlinkInode); } else { *outUnlinkInode = NULL; // irrelevant values, just to please the compiler unlinkRes = FhgfsOpsErr_SUCCESS; unlinkedWasInlined = true; } /* Now update the ctime (attribChangeTime) of the renamed entry. * Only do that for Directory dentry after giving up the DirInodes (fromMutex) lock * as dirStore.setAttr() will aquire the InodeDirStore:: lock * and the lock order is InodeDirStore:: and then DirInode:: (risk of deadlock) */ DirEntry* entry = parentDir->dirEntryCreateFromFileUnlocked(toName); if (likely(entry) ) // entry was just renamed to, so very likely it exists { EntryInfo entryInfo; std::string parentID = parentDir->getID(); entry->getEntryInfo(parentID, 0, &entryInfo); fromMutexLock.unlock(); setAttrUnlocked(&entryInfo, 0, NULL); /* This will fail if the DirInode is on another * meta server, but as updating the ctime is not * a real posix requirement (but filesystems usually * do it) we simply ignore this issue for now. */ SAFE_DELETE(entry); } else fromMutexLock.unlock(); safeLock.unlock(); // unlink later must be called after releasing all locks if (overWrittenEntry) { if (unlinkRes == FhgfsOpsErr_INUSE) { unlinkRes = unlinkInodeLater(&unlinkEntryInfo, unlinkedWasInlined ); if (unlinkRes == FhgfsOpsErr_AGAIN) { unlinkRes = unlinkOverwrittenEntry(parentDir, overWrittenEntry, outUnlinkInode); } } if (unlinkRes != FhgfsOpsErr_SUCCESS && unlinkRes != FhgfsOpsErr_PATHNOTEXISTS) { LogContext(logContext).logErr("Failed to unlink overwritten entry:" " FileName: " + toName + " ParentEntryID: " + parentDir->getID() + " entryID: " + overWrittenEntry->getEntryID() + " Error: " + FhgfsOpsErrTk::toErrString(unlinkRes) ); // TODO: Restore the dentry } } SAFE_DELETE(overWrittenEntry); return retVal; }