#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RenameV2MsgEx.h" #include namespace { struct DirHandle { MetaStore* metaStore; const EntryInfo* ei; DirHandle(MetaStore* metaStore, const EntryInfo* ei): metaStore(metaStore), ei(ei) {} DirHandle(const DirHandle&) = delete; DirHandle(DirHandle&&) = delete; DirHandle& operator=(const DirHandle&) = delete; DirHandle& operator=(DirHandle&&) = delete; ~DirHandle() { metaStore->releaseDir(ei->getEntryID()); } }; } RenameV2Locks RenameV2MsgEx::lock(EntryLockStore& store) { MetaStore* metaStore = Program::getApp()->getMetaStore(); // if the directory could not be referenced it does not exist on the current node. this will // cause the operation to fail lateron during executeLocally() when we reference the same // directory again. since we cannot do anything without having access to the source directory, // and since no directory with the same id as the source directory can appear after the source // directory has been removed, we can safely unlock everything right here and continue without // blocking other workers on the (probably live) target directory. DirInode* fromDir = metaStore->referenceDir(getFromDirInfo()->getEntryID(), getFromDirInfo()->getIsBuddyMirrored(), true); if (!fromDir) return {}; const DirHandle _from(metaStore, getFromDirInfo()); DirInode* toDir = metaStore->referenceDir(getToDirInfo()->getEntryID(), getToDirInfo()->getIsBuddyMirrored(), true); if (!toDir) return {}; const DirHandle _to(metaStore, getToDirInfo()); for (;;) { RenameV2Locks result; EntryInfo fromFileInfo; EntryInfo toFileInfo; fromDir->getFileEntryInfo(getOldName(), fromFileInfo); bool toFileExists = toDir->getFileEntryInfo(getNewName(), toFileInfo); if (toFileExists && DirEntryType_ISFILE(toFileInfo.getEntryType())) { // lock hash dir of tofile inode only if: // 1) its a file and // 2) its a non-inlined inode and // 3) resynch job is running if (resyncJob && resyncJob->isRunning() && !toFileInfo.getIsInlined()) result.toFileHashLock = {&store, MetaStorageTk::getMetaInodeHash(toFileInfo.getEntryID())}; } { std::map lockOrder; lockOrder.insert(std::make_pair(getFromDirInfo()->getEntryID(), &result.fromDirLock)); lockOrder.insert(std::make_pair(getToDirInfo()->getEntryID(), &result.toDirLock)); if (DirEntryType_ISDIR(fromFileInfo.getEntryType())) lockOrder.insert(std::make_pair(fromFileInfo.getEntryID(), &result.fromFileLockD)); for (auto it = lockOrder.begin(); it != lockOrder.end(); ++it) *it->second = {&store, it->first, true}; } // we might have locked fromFileLockD before fromDirLock due to ordering. resolve the source // once more and check that we still refer to the same id, otherwise retry until we have the // correct inode. // if the name went away we don't have to retry (it can't be created while the dir is locked), // but retrying is simpler to do. EntryInfo fromFileInfoCheck; fromDir->getFileEntryInfo(getOldName(), fromFileInfoCheck); if (fromFileInfo.getEntryID() != fromFileInfoCheck.getEntryID()) continue; // take care about lock ordering! see MirroredMessage::lock() // since directories are locked for read, and by the same id as the (parent,name) tuples,the // same ordering applies. if (getFromDirInfo()->getEntryID() < getToDirInfo()->getEntryID()) { result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()}; result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()}; } else if (getFromDirInfo()->getEntryID() == getToDirInfo()->getEntryID()) { if (getOldName() < getNewName()) { result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()}; result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()}; } else if (getOldName() == getNewName()) { result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()}; } else { result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()}; result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()}; } } else { result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()}; result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()}; } if (DirEntryType_ISFILE(fromFileInfo.getEntryType()) && fromFileInfo.getIsInlined()) { if (DirEntryType_ISFILE(toFileInfo.getEntryType()) && toFileInfo.getIsInlined()) { if (fromFileInfo.getEntryID() < toFileInfo.getEntryID()) { result.fromFileLockF = {&store, fromFileInfo.getEntryID(), true}; result.unlinkedFileLock = {&store, toFileInfo.getEntryID(), true}; } else if (fromFileInfo.getEntryID() == toFileInfo.getEntryID()) { result.fromFileLockF = {&store, fromFileInfo.getEntryID(), true}; } else { result.unlinkedFileLock = {&store, toFileInfo.getEntryID(), true}; result.fromFileLockF = {&store, fromFileInfo.getEntryID(), true}; } } else { result.fromFileLockF = {&store, fromFileInfo.getEntryID(), true}; } } return result; } } bool RenameV2MsgEx::processIncoming(ResponseContext& ctx) { LOG_DEBUG(__func__, Log_DEBUG, "FromDirID: " + getFromDirInfo()->getEntryID() + "; " "oldName: '" + getOldName() + "'; " "ToDirID: " + getToDirInfo()->getEntryID() + "; " "newName: '" + getNewName() + "'"); BaseType::processIncoming(ctx); // update operation counters updateNodeOp(ctx, MetaOpCounter_RENAME); return true; } /** * Checks existence of the from-part and calls movingPerform(). */ std::unique_ptr RenameV2MsgEx::executeLocally(ResponseContext& ctx, bool isSecondary) { App* app = Program::getApp(); MetaStore* metaStore = app->getMetaStore(); // reference fromParent DirInode* fromParent = metaStore->referenceDir(getFromDirInfo()->getEntryID(), getFromDirInfo()->getIsBuddyMirrored(), true); if (unlikely(!fromParent)) return boost::make_unique(FhgfsOpsErr_PATHNOTEXISTS); std::string unlinkedEntryID; // ID of potential overwritten destination file for cleanup EntryInfo srcEntryInfo; // EntryInfo of source file/directory being renamed unsigned srcEntryLinkCount = 0; // Hardlink count needed for event logging ModificationEventFlusher* modEventFlusher = app->getModificationEventFlusher(); const bool modEventLoggingEnabled = modEventFlusher->isLoggingEnabled(); const bool fileEventLogEnabled = !isSecondary && getFileEvent() && app->getFileEventLogger(); if (modEventLoggingEnabled || fileEventLogEnabled) { fromParent->getEntryInfo(getOldName(), srcEntryInfo); // Fetch link count early before rename occurs: // - Inlined inode data might move to a different metadata node post-rename // - Early fetch avoids a StatMsg round trip to retrieve link count from the new node FhgfsOpsErr res; std::tie(res, srcEntryLinkCount) = getLinkCountForMovedEntry(&srcEntryInfo); if (res != FhgfsOpsErr_SUCCESS) { LogContext("RenameV2MsgEx::executeLocally").logErr( "Failed to get link count for entry: " + srcEntryInfo.getEntryID()); // don't return an error to client } } FhgfsOpsErr renameRes = movingPerform(*fromParent, getOldName(), getEntryType(), getToDirInfo(), getNewName(), unlinkedEntryID); if ((renameRes == FhgfsOpsErr_SUCCESS) && shouldFixTimestamps()) fixInodeTimestamp(*fromParent, fromDirTimestamps); metaStore->releaseDir(getFromDirInfo()->getEntryID()); if ((renameRes == FhgfsOpsErr_SUCCESS) && fileEventLogEnabled) { EventContext eventCtx = makeEventContext( &srcEntryInfo, getFromDirInfo()->getEntryID(), getMsgHeaderUserID(), getToDirInfo()->getEntryID(), srcEntryLinkCount, isSecondary ); logEvent(app->getFileEventLogger(), *getFileEvent(), eventCtx); } // clean-up if ((renameRes == FhgfsOpsErr_SUCCESS) && modEventLoggingEnabled) { if (DirEntryType_ISDIR(getEntryType())) modEventFlusher->add(ModificationEvent_DIRMOVED, srcEntryInfo.getEntryID()); else { modEventFlusher->add(ModificationEvent_FILEMOVED, srcEntryInfo.getEntryID()); if (!unlinkedEntryID.empty()) modEventFlusher->add(ModificationEvent_FILEREMOVED, unlinkedEntryID); } } return boost::make_unique(renameRes); } FhgfsOpsErr RenameV2MsgEx::movingPerform(DirInode& fromParent, const std::string& oldName, DirEntryType entryType, EntryInfo* toDirInfo, const std::string& newName, std::string& unlinkedEntryID) { const char* logContext = "RenameV2MsgEx::movingPerform"; IGNORE_UNUSED_VARIABLE(logContext); App* app = Program::getApp(); // is this node the owner of the fromParent dir? MirrorBuddyGroupMapper* metaBuddyGroupMapper = app->getMetaBuddyGroupMapper(); NumNodeID expectedOwnerID = fromParent.getIsBuddyMirrored() ? NumNodeID(metaBuddyGroupMapper->getLocalGroupID() ) : app->getLocalNode().getNumID(); if (fromParent.getOwnerNodeID() != expectedOwnerID) return FhgfsOpsErr_NOTOWNER; if (unlikely(entryType == DirEntryType_INVALID) ) { LOG_DEBUG(logContext, Log_SPAM, "Received an invalid entry type!"); return FhgfsOpsErr_INTERNAL; } FhgfsOpsErr retVal = FhgfsOpsErr_INTERNAL; if (fromParent.getID() == toDirInfo->getEntryID()) { // simple rename (<= not a move && everything local) LOG_DEBUG(logContext, Log_SPAM, "Method: rename in same dir"); // debug in retVal = renameInSameDir(fromParent, oldName, newName, unlinkedEntryID); } else if (entryType == DirEntryType_DIRECTORY) retVal = renameDir(fromParent, oldName, toDirInfo, newName); else retVal = renameFile(fromParent, oldName, toDirInfo, newName, unlinkedEntryID); return retVal; } void RenameV2MsgEx::forwardToSecondary(ResponseContext& ctx) { sendToSecondary(ctx, *this, NETMSGTYPE_RenameResp); } /** * Rename a directory */ FhgfsOpsErr RenameV2MsgEx::renameDir(DirInode& fromParent, const std::string& oldName, EntryInfo* toDirInfo, const std::string& newName) { const char* logContext = "RenameV2MsgEx::renameDir"; FhgfsOpsErr retVal = FhgfsOpsErr_INTERNAL; DirEntry fromDirEntry(oldName); bool dirEntryCopyRes = fromParent.getDirDentry(oldName, fromDirEntry); if (!dirEntryCopyRes) { LOG_DEBUG("RenameV2MsgEx::movingPerform", Log_SPAM, "getDirEntryCopy() failed"); return FhgfsOpsErr_NOTADIR; } // when we we verified the 'oldName' is really a directory LOG_DEBUG(logContext, Log_SPAM, "Method: remote dir move."); // debug in if (fromParent.getIsBuddyMirrored() && hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond)) { retVal = FhgfsOpsErr_SUCCESS; } else { // prepare local part of the move operation boost::scoped_array serialBuf(new char[META_SERBUF_SIZE]); Serializer ser(serialBuf.get(), META_SERBUF_SIZE); /* Put all meta data of this dentry into the given buffer. The buffer then will be * used on the remote side to fill the new dentry */ fromDirEntry.serializeDentry(ser); if (!ser.good()) LogContext(logContext).logErr("dentry too large: " + oldName); else retVal = remoteDirInsert(toDirInfo, newName, serialBuf.get(), ser.size()); } // finish local part of the move operation if (retVal == FhgfsOpsErr_SUCCESS) { DirEntry* rmDirEntry; retVal = fromParent.removeDir(oldName, &rmDirEntry); if (retVal == FhgfsOpsErr_SUCCESS) { std::string parentID = fromParent.getID(); EntryInfo removedInfo; rmDirEntry->getEntryInfo(parentID, 0, &removedInfo); if (!hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond)) updateRenamedDirInode(&removedInfo, toDirInfo); } else { LogContext(logContext).log(Log_CRITICAL, std::string("Failed to remove fromDir: ") + oldName + " Error: " + boost::lexical_cast(retVal)); } SAFE_DELETE(rmDirEntry); } return retVal; } /** * Rename a file */ FhgfsOpsErr RenameV2MsgEx::renameFile(DirInode& fromParent, const std::string& oldName, EntryInfo* toDirInfo, const std::string& newName, std::string& unlinkedEntryID) { const char* logContext = "RenameV2MsgEx::renameFile"; MetaStore* metaStore = Program::getApp()->getMetaStore(); FhgfsOpsErr retVal = FhgfsOpsErr_INTERNAL; EntryInfo fromFileInfo; bool getRes = fromParent.getFileEntryInfo(oldName, fromFileInfo); if (!getRes) { LOG_DEBUG(logContext, Log_SPAM, "Error: fromDir does not exist."); return FhgfsOpsErr_PATHNOTEXISTS; } // when we are here we verified the file to be renamed is really a file if (fromParent.getIsBuddyMirrored() && hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond)) { retVal = FhgfsOpsErr_SUCCESS; } else { // the buffer is used to transfer all data of the dir-entry boost::scoped_array serialBuf(new char[META_SERBUF_SIZE]); size_t usedSerialBufLen; retVal = metaStore->moveRemoteFileBegin( fromParent, &fromFileInfo, serialBuf.get(), META_SERBUF_SIZE, &usedSerialBufLen); if (retVal != FhgfsOpsErr_SUCCESS) return retVal; LOG_DEBUG(logContext, Log_SPAM, "Method: remote file move."); // debug in StringVector xattrNames; if (Program::getApp()->getConfig()->getStoreClientXAttrs() && fromFileInfo.getIsInlined()) { FhgfsOpsErr listXAttrRes; std::tie(listXAttrRes, xattrNames) = MsgHelperXAttr::listxattr(&fromFileInfo); if (listXAttrRes != FhgfsOpsErr_SUCCESS) { metaStore->moveRemoteFileComplete(fromParent, fromFileInfo.getEntryID()); return FhgfsOpsErr_TOOBIG; } } // Do the remote operation (insert and possible unlink of an existing toFile) retVal = remoteFileInsertAndUnlink(&fromFileInfo, toDirInfo, newName, serialBuf.get(), usedSerialBufLen, std::move(xattrNames), unlinkedEntryID); } // finish local part of the owned file move operation (+ remove local file-link) if (retVal == FhgfsOpsErr_SUCCESS) { FhgfsOpsErr unlinkRes; if (fromFileInfo.getIsInlined()) { // We are not interested in the inode here , as we are not going to delete storage chunks. EntryInfo entryInfo; unsigned outNumHardlinks; // Not used here! unlinkRes = metaStore->unlinkFile(fromParent, oldName, &entryInfo, NULL, outNumHardlinks); } else { // only unlink dentry-by-filename for nonInlined inode(s) DirEntry oldDentry(oldName); if (fromParent.getDentry(oldName, oldDentry)) unlinkRes = fromParent.unlinkDirEntry(oldName, &oldDentry, DirEntry_UNLINK_FILENAME); else unlinkRes = FhgfsOpsErr_PATHNOTEXISTS; } if (unlikely (unlinkRes) ) { LogContext(logContext).logErr(std::string("Error: Failed to unlink fromFile: ") + "DirID: " + fromFileInfo.getParentEntryID() + " " "entryName: " + oldName + ". " + "Remote toFile was successfully created."); } } if (!fromParent.getIsBuddyMirrored() || !hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond)) metaStore->moveRemoteFileComplete(fromParent, fromFileInfo.getEntryID() ); return retVal; } /** * Renames a directory or a file (no moving between different directories involved). */ FhgfsOpsErr RenameV2MsgEx::renameInSameDir(DirInode& fromParent, const std::string& oldName, const std::string& toName, std::string& unlinkedEntryID) { const char* logContext = "RenameV2MsgEx::renameInSameDir"; MetaStore* metaStore = Program::getApp()->getMetaStore(); /* we are passing here the very same fromParent pointer also a toParent pointer, which is * essential in order not to dead-lock */ std::unique_ptr unlinkInode; // inode belong to a possibly existing toName file DirEntry* overWrittenEntry = NULL; bool wasInlined; // to determine if overwritten inode was inlined or not FhgfsOpsErr renameRes = metaStore->renameInSameDir(fromParent, oldName, toName, &unlinkInode, overWrittenEntry, wasInlined); if (renameRes == FhgfsOpsErr_SUCCESS) { if (shouldFixTimestamps()) { DirEntry dentry(toName); if (fromParent.getDentry(toName, dentry)) { EntryInfo info; dentry.getEntryInfo(fromParent.getID(), 0, &info); if (DirEntryType_ISDIR(info.getEntryType())) { auto dir = metaStore->referenceDir(info.getEntryID(), info.getIsBuddyMirrored(), true); if (dir) { fixInodeTimestamp(*dir, renamedInodeTimestamps); metaStore->releaseDir(dir->getID()); } } else { auto [file, referenceRes] = metaStore->referenceFile(&info); if (file) { fixInodeTimestamp(*file, renamedInodeTimestamps, &info); metaStore->releaseFile(fromParent.getID(), file); } } } } if (overWrittenEntry && !overWrittenEntry->getIsInodeInlined()) { EntryInfo overWrittenEntryInfo; overWrittenEntry->getEntryInfo(fromParent.getID(), 0, &overWrittenEntryInfo); if (wasInlined) { // if overwritten file previously had an inlined inode which got de-inlined because // it was IN_USE during rename operation - in this case, its inode should already be // linked to disposal directory and will be removed upon close() return renameRes; } else if (!hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond)) { // if overwritten file had a non-inlined inode - update hardlink count and remove // inode and chunk files if link count becomes zero unlinkRemoteFileInode(&overWrittenEntryInfo); } } // handle unlinkInode for inlined inode(s) if (unlinkInode && !hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond)) { unlinkedEntryID = unlinkInode->getEntryID(); FhgfsOpsErr chunkUnlinkRes = MsgHelperUnlink::unlinkChunkFiles( unlinkInode.release(), getMsgHeaderUserID() ); if (chunkUnlinkRes != FhgfsOpsErr_SUCCESS) { LogContext(logContext).logErr(std::string("Rename succeeded, but unlinking storage ") + "chunk files of the overwritten targetFileName (" + toName + ") failed. " + "Entry-ID: " + unlinkedEntryID); // we can't do anything about it, so we won't even inform the user } } } return renameRes; } /** * Note: This method not only sends the insertion message, but also unlinks an overwritten local * file if it is contained in the response. * * @param serialBuf the inode values serialized into this buffer. */ FhgfsOpsErr RenameV2MsgEx::remoteFileInsertAndUnlink(EntryInfo* fromFileInfo, EntryInfo* toDirInfo, std::string newName, char* serialBuf, size_t serialBufLen, StringVector xattrs, std::string& unlinkedEntryID) { LogContext log("RenameV2MsgEx::remoteFileInsert"); FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS; App* app = Program::getApp(); NumNodeID toNodeID = toDirInfo->getOwnerNodeID(); LOG_DEBUG_CONTEXT(log, Log_DEBUG, "Inserting remote parentID: " + toDirInfo->getEntryID() + "; " "newName: '" + newName + "'; " "entryID: '" + fromFileInfo->getEntryID() + "'; " "node: " + toNodeID.str() ); // prepare request MovingFileInsertMsg insertMsg(fromFileInfo, toDirInfo, newName, serialBuf, serialBufLen); RequestResponseArgs rrArgs(NULL, &insertMsg, NETMSGTYPE_MovingFileInsertResp); RequestResponseNode rrNode(toNodeID, app->getMetaNodes() ); rrNode.setTargetStates(app->getMetaStateStore() ); if (toDirInfo->getIsBuddyMirrored()) rrNode.setMirrorInfo(app->getMetaBuddyGroupMapper(), false); // send request and receive response MsgHelperXAttr::StreamXAttrState streamState(*fromFileInfo, std::move(xattrs)); insertMsg.registerStreamoutHook(rrArgs, streamState); FhgfsOpsErr requestRes = MessagingTk::requestResponseNode(&rrNode, &rrArgs); if(requestRes != FhgfsOpsErr_SUCCESS) { // communication error log.log(Log_WARNING, "Communication with metadata sever failed. nodeID: " + toNodeID.str() ); return requestRes; } // correct response type received const auto insertRespMsg = (MovingFileInsertRespMsg*)rrArgs.outRespMsg.get(); retVal = insertRespMsg->getResult(); // handle unlink of chunk files for inlined inode(s) // handle unlink of inode for non-inlined inode(s) EntryInfo* overWrittenInfo = insertRespMsg->getOverWrittenEntryInfo(); if (overWrittenInfo->getEntryType() != DirEntryType_INVALID) { if (overWrittenInfo->getIsInlined()) { unsigned unlinkedInodeBufLen = insertRespMsg->getInodeBufLen(); if (unlinkedInodeBufLen) { const char* unlinkedInodeBuf = insertRespMsg->getInodeBuf(); FileInode* toUnlinkInode = new FileInode(); Deserializer des(unlinkedInodeBuf, unlinkedInodeBufLen); toUnlinkInode->deserializeMetaData(des); if(unlikely(!des.good())) { // deserialization of received inode failed (should never happen) log.logErr("Failed to deserialize unlinked file inode. nodeID: " + toNodeID.str() ); delete(toUnlinkInode); } else if (toUnlinkInode->getIsInlined()) { MsgHelperUnlink::unlinkChunkFiles( toUnlinkInode, getMsgHeaderUserID() ); // destructs toUnlinkInode } } } else { unlinkRemoteFileInode(overWrittenInfo); } } if (retVal != FhgfsOpsErr_SUCCESS) { // error: remote file not inserted LOG_DEBUG_CONTEXT(log, Log_NOTICE, "Metadata server was unable to insert file. " "nodeID: " + toNodeID.str() + "; " "Error: " + boost::lexical_cast(retVal)); } else { // success: remote file inserted LOG_DEBUG_CONTEXT(log, Log_DEBUG, "Metadata server inserted file. " "nodeID: " + toNodeID.str() ); } return retVal; } /** * Insert a remote directory dir-entry */ FhgfsOpsErr RenameV2MsgEx::remoteDirInsert(EntryInfo* toDirInfo, const std::string& newName, char* serialBuf, size_t serialBufLen) { LogContext log("RenameV2MsgEx::remoteDirInsert"); FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS; App* app = Program::getApp(); NumNodeID toNodeID = toDirInfo->getOwnerNodeID(); LOG_DEBUG_CONTEXT(log, Log_DEBUG, "Inserting remote parentID: " + toDirInfo->getEntryID() + "; " "newName: '" + newName + "'; " "node: " + toNodeID.str() ); // prepare request MovingDirInsertMsg insertMsg(toDirInfo, newName, serialBuf, serialBufLen); RequestResponseArgs rrArgs(NULL, &insertMsg, NETMSGTYPE_MovingDirInsertResp); RequestResponseNode rrNode(toNodeID, app->getMetaNodes() ); rrNode.setTargetStates(app->getMetaStateStore() ); if (toDirInfo->getIsBuddyMirrored()) rrNode.setMirrorInfo(app->getMetaBuddyGroupMapper(), false); // send request and receive response FhgfsOpsErr requestRes = MessagingTk::requestResponseNode(&rrNode, &rrArgs); if(requestRes != FhgfsOpsErr_SUCCESS) { // communication error log.log(Log_WARNING, "Communication with metadata server failed. nodeID: " + toNodeID.str() ); return requestRes; } // correct response type received const auto insertRespMsg = (const MovingDirInsertRespMsg*)rrArgs.outRespMsg.get(); retVal = insertRespMsg->getResult(); if(retVal != FhgfsOpsErr_SUCCESS) { // error: remote dir not inserted LOG_DEBUG_CONTEXT(log, Log_NOTICE, "Metdata server was unable to insert directory. " "nodeID: " + toNodeID.str() + "; " "Error: " + boost::lexical_cast(retVal)); } else { // success: remote dir inserted LOG_DEBUG_CONTEXT(log, Log_DEBUG, "Metadata server inserted directory. " "nodeID: " + toNodeID.str() ); } return retVal; } /** * Set the new parent information to the inode of renamedDirEntryInfo */ FhgfsOpsErr RenameV2MsgEx::updateRenamedDirInode(EntryInfo* renamedDirEntryInfo, EntryInfo* toDirInfo) { LogContext log("RenameV2MsgEx::updateRenamedDirInode"); const std::string& parentEntryID = toDirInfo->getEntryID(); renamedDirEntryInfo->setParentEntryID(parentEntryID); App* app = Program::getApp(); NumNodeID toNodeID = renamedDirEntryInfo->getOwnerNodeID(); LOG_DEBUG_CONTEXT(log, Log_DEBUG, "Update remote inode: " + renamedDirEntryInfo->getEntryID() + "; " "node: " + toNodeID.str() ); // prepare request UpdateDirParentMsg updateMsg(renamedDirEntryInfo, toDirInfo->getOwnerNodeID() ); RequestResponseArgs rrArgs(NULL, &updateMsg, NETMSGTYPE_UpdateDirParentResp); RequestResponseNode rrNode(toNodeID, app->getMetaNodes() ); rrNode.setTargetStates(app->getMetaStateStore() ); if (renamedDirEntryInfo->getIsBuddyMirrored()) rrNode.setMirrorInfo(app->getMetaBuddyGroupMapper(), false); // send request and receive response FhgfsOpsErr requestRes = MessagingTk::requestResponseNode(&rrNode, &rrArgs); if(requestRes != FhgfsOpsErr_SUCCESS) { // communication error log.log(Log_WARNING, "Communication with metadata server failed. nodeID: " + toNodeID.str() ); return requestRes; } // correct response type received const auto updateRespMsg = (const UpdateDirParentRespMsg*)rrArgs.outRespMsg.get(); FhgfsOpsErr retVal = (FhgfsOpsErr)updateRespMsg->getValue(); if(retVal != FhgfsOpsErr_SUCCESS) { // error LOG_DEBUG_CONTEXT(log, Log_NOTICE, "Failed to update ParentEntryID: " + renamedDirEntryInfo->getEntryID() + "; " "nodeID: " + toNodeID.str() + "; " "Error: " + boost::lexical_cast(retVal)); } return retVal; } /* * Handle unlink for a non-inlined inode * Decrement hardLink count, if linkCount becomes zero then remove inode and chunk files */ FhgfsOpsErr RenameV2MsgEx::unlinkRemoteFileInode(EntryInfo* entryInfo) { const char* logContext = "Unlink remote file inode"; App* app = Program::getApp(); FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS; NumNodeID ownerNodeID = entryInfo->getOwnerNodeID(); UnlinkLocalFileInodeMsg unlinkInodeMsg(entryInfo); RequestResponseArgs rrArgs(NULL, &unlinkInodeMsg, NETMSGTYPE_UnlinkLocalFileInodeResp); RequestResponseNode rrNode(ownerNodeID, app->getMetaNodes()); if (entryInfo->getIsBuddyMirrored()) rrNode.setMirrorInfo(Program::getApp()->getMetaBuddyGroupMapper(), false); do { retVal = MessagingTk::requestResponseNode(&rrNode, &rrArgs); if (unlikely(retVal != FhgfsOpsErr_SUCCESS)) { LogContext(logContext).log(Log_WARNING, "Communication with metadata server failed. " "nodeID: " + ownerNodeID.str() + "; " + "entryID: " + entryInfo->getEntryID().c_str()); break; } // response received const auto unlinkFileInodeRespMsg = (UnlinkLocalFileInodeRespMsg*) rrArgs.outRespMsg.get(); retVal = unlinkFileInodeRespMsg->getResult(); if (retVal != FhgfsOpsErr_SUCCESS) { // error: either inode file doesn't exists or some other error happened LogContext(logContext).logErr("unlink of inode failed! " "nodeID: " + ownerNodeID.str() + "; " + "entryID: " + entryInfo->getEntryID().c_str()); break; } } while (false); return retVal; } std::pair RenameV2MsgEx::getLinkCountForMovedEntry(EntryInfo* entryInfo) { const char* logContext = "RenameV2Msg (Get Link Count)"; App* app = Program::getApp(); FhgfsOpsErr statRes = FhgfsOpsErr_SUCCESS; unsigned linkCount = 0; NumNodeID ownerNodeID = entryInfo->getOwnerNodeID(); bool isLocalOwner = ((!isMirrored() && ownerNodeID == app->getLocalNode().getNumID()) || (isMirrored() && ownerNodeID.val() == app->getMetaBuddyGroupMapper()->getLocalGroupID())); if (isLocalOwner) { StatData statData; statRes = MsgHelperStat::stat(entryInfo, true, getMsgHeaderUserID(), statData); if (statRes == FhgfsOpsErr_SUCCESS) linkCount = statData.getNumHardlinks(); else LogContext(logContext).logErr("Stat Failed!. entryID: " + entryInfo->getEntryID()); } else { // send StatMsg to remote meta node/buddygroup StatMsg statMsg(entryInfo); RequestResponseArgs rrArgs(NULL, &statMsg, NETMSGTYPE_StatResp); RequestResponseNode rrNode(ownerNodeID, app->getMetaNodes()); rrNode.setTargetStates(app->getMetaStateStore()); if (entryInfo->getIsBuddyMirrored()) rrNode.setMirrorInfo(app->getMetaBuddyGroupMapper(), false); do { FhgfsOpsErr resp = MessagingTk::requestResponseNode(&rrNode, &rrArgs); if (unlikely(resp != FhgfsOpsErr_SUCCESS)) { LogContext(logContext).logErr("Communication with metadata server failed. " "nodeID: " + ownerNodeID.str()); statRes = resp; break; } // response received const auto statRespMsg = (StatRespMsg*) rrArgs.outRespMsg.get(); statRes = (FhgfsOpsErr) statRespMsg->getResult(); if (statRes != FhgfsOpsErr_SUCCESS) { LogContext(logContext).logErr("Stat Failed!. nodeID: " + ownerNodeID.str() + "; entryID: " + entryInfo->getEntryID()); break; } // success linkCount = statRespMsg->getStatData()->getNumHardlinks(); } while (false); } return {statRes, linkCount}; }