#include #include #include #include #include #include #include #include #include #include #include "RmDirMsgEx.h" bool RmDirMsgEx::processIncoming(ResponseContext& ctx) { BaseType::processIncoming(ctx); // update operation counters updateNodeOp(ctx, MetaOpCounter_RMDIR); return true; } std::tuple RmDirMsgEx::lock(EntryLockStore& store) { MetaStore* metaStore = Program::getApp()->getMetaStore(); EntryInfo delEntryInfo; DirInode* parentDir = metaStore->referenceDir( getParentInfo()->getEntryID(), getParentInfo()->getIsBuddyMirrored(), true); if (!parentDir) return {}; else { parentDir->getDirEntryInfo(getDelDirName(), delEntryInfo); metaStore->releaseDir(getParentInfo()->getEntryID()); } FileIDLock parentDirLock; FileIDLock delDirLock; HashDirLock hashLock; if (resyncJob && resyncJob->isRunning()) hashLock = {&store, MetaStorageTk::getMetaInodeHash(delEntryInfo.getEntryID())}; // lock directories in deadlock-avoidance order, see MirroredMessage::lock() if (delEntryInfo.getEntryID().empty()) { parentDirLock = {&store, getParentInfo()->getEntryID(), true}; } else if (delEntryInfo.getEntryID() < getParentInfo()->getEntryID()) { delDirLock = {&store, delEntryInfo.getEntryID(), true}; parentDirLock = {&store, getParentInfo()->getEntryID(), true}; } else if (delEntryInfo.getEntryID() == getParentInfo()->getEntryID()) { delDirLock = {&store, delEntryInfo.getEntryID(), true}; } else { parentDirLock = {&store, getParentInfo()->getEntryID(), true}; delDirLock = {&store, delEntryInfo.getEntryID(), true}; } ParentNameLock parentNameLock(&store, getParentInfo()->getEntryID(), getDelDirName()); return std::make_tuple( std::move(hashLock), std::move(parentDirLock), std::move(delDirLock), std::move(parentNameLock)); } std::unique_ptr RmDirMsgEx::rmDir(ResponseContext& ctx, const bool isSecondary) { App* app = Program::getApp(); MetaStore* metaStore = Program::getApp()->getMetaStore(); ModificationEventFlusher* modEventFlusher = Program::getApp()->getModificationEventFlusher(); bool modEventLoggingEnabled = modEventFlusher->isLoggingEnabled(); FhgfsOpsErr retVal; EntryInfo* parentInfo = this->getParentInfo(); const std::string& delDirName = this->getDelDirName(); EntryInfo outDelEntryInfo; // reference parent DirInode* parentDir = metaStore->referenceDir(parentInfo->getEntryID(), parentInfo->getIsBuddyMirrored(), true); if(!parentDir) return boost::make_unique(FhgfsOpsErr_PATHNOTEXISTS); DirEntry removeDirEntry(delDirName); bool getEntryRes = parentDir->getDirDentry(delDirName, removeDirEntry); if(!getEntryRes) retVal = FhgfsOpsErr_PATHNOTEXISTS; else { int additionalFlags = 0; const std::string& parentEntryID = parentInfo->getEntryID(); removeDirEntry.getEntryInfo(parentEntryID, additionalFlags, &outDelEntryInfo); App* app = Program::getApp(); NumNodeID ownerNodeID = outDelEntryInfo.getOwnerNodeID(); // no-comms path: the dir inode is owned by us if ((!isMirrored() && ownerNodeID == app->getLocalNode().getNumID()) || (isMirrored() && ownerNodeID.val() == app->getMetaBuddyGroupMapper()->getLocalGroupID())) retVal = app->getMetaStore()->removeDirInode(outDelEntryInfo.getEntryID(), outDelEntryInfo.getIsBuddyMirrored()); else if (!isSecondary) retVal = rmRemoteDirInode(&outDelEntryInfo); else retVal = FhgfsOpsErr_SUCCESS; if(retVal == FhgfsOpsErr_SUCCESS) { // local removal succeeded => remove meta dir retVal = parentDir->removeDir(delDirName, NULL); } } if (retVal == FhgfsOpsErr_SUCCESS && shouldFixTimestamps()) fixInodeTimestamp(*parentDir, dirTimestamps); // clean-up metaStore->releaseDir(parentInfo->getEntryID() ); if (!isSecondary && retVal == FhgfsOpsErr_SUCCESS && app->getFileEventLogger() && getFileEvent()) { EventContext eventCtx = makeEventContext(&outDelEntryInfo, outDelEntryInfo.getParentEntryID(), getMsgHeaderUserID(), "", 0, isSecondary); logEvent(app->getFileEventLogger(), *getFileEvent(), eventCtx); } if (retVal == FhgfsOpsErr_SUCCESS && modEventLoggingEnabled) { const std::string& entryID = outDelEntryInfo.getEntryID(); modEventFlusher->add(ModificationEvent_DIRREMOVED, entryID); } return boost::make_unique(retVal); } /** * Remove the inode of this directory */ FhgfsOpsErr RmDirMsgEx::rmRemoteDirInode(EntryInfo* delEntryInfo) { const char* logContext = "RmDirMsg (rm dir inode)"; FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS; App* app = Program::getApp(); NumNodeID ownerNodeID = delEntryInfo->getOwnerNodeID(); LOG_DEBUG(logContext, Log_DEBUG, "Removing dir inode from metadata node: " + ownerNodeID.str() + "; " "dirname: " + delEntryInfo->getFileName() + "; isBuddyMirrored: " + StringTk::intToStr(delEntryInfo->getIsBuddyMirrored()) ); // prepare request RmLocalDirMsg rmMsg(delEntryInfo); RequestResponseArgs rrArgs(NULL, &rmMsg, NETMSGTYPE_RmLocalDirResp); RequestResponseNode rrNode(ownerNodeID, app->getMetaNodes() ); rrNode.setTargetStates(app->getMetaStateStore() ); if (delEntryInfo->getIsBuddyMirrored()) rrNode.setMirrorInfo(app->getMetaBuddyGroupMapper(), false); do // (this loop just exists to enable the "break"-jump, so it's not really a loop) { // send request to other mds and receive response FhgfsOpsErr requestRes = MessagingTk::requestResponseNode(&rrNode, &rrArgs); if(requestRes != FhgfsOpsErr_SUCCESS) { // communication error LogContext(logContext).log(Log_WARNING, "Communication with metadata server failed. " "ownerNodeID: " + ownerNodeID.str() + "; " "dirID: " + delEntryInfo->getEntryID() + "; " + "dirname: " + delEntryInfo->getFileName() ); retVal = requestRes; break; } // correct response type received const auto rmRespMsg = (const RmLocalDirRespMsg*)rrArgs.outRespMsg.get(); retVal = rmRespMsg->getResult(); if(unlikely( (retVal != FhgfsOpsErr_SUCCESS) && (retVal != FhgfsOpsErr_NOTEMPTY) ) ) { // error: dir inode not removed std::string errString = boost::lexical_cast(retVal); LogContext(logContext).log(Log_DEBUG, "Metadata server was unable to remove dir inode. " "ownerNodeID: " + ownerNodeID.str() + "; " "dirID: " + delEntryInfo->getEntryID() + "; " + "dirname: " + delEntryInfo->getFileName() + "; " + "error: " + errString); break; } // success: dir inode removed LOG_DEBUG(logContext, Log_DEBUG, "Metadata server removed dir inode: " "ownerNodeID: " + ownerNodeID.str() + "; " "dirID: " + delEntryInfo->getEntryID() + "; " + "dirname: " + delEntryInfo->getFileName() ); } while(false); return retVal; } void RmDirMsgEx::forwardToSecondary(ResponseContext& ctx) { sendToSecondary(ctx, *this, NETMSGTYPE_RmDirResp); }